home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 6 / Night Owl's Shareware - PDSI-006 - Night Owl Corp (1990).iso / 001a / mskrmsrc.zip / MSSKER.ASM < prev    next >
Assembly Source File  |  1991-10-24  |  75KB  |  2,359 lines

  1.     NAME    mssker
  2. ; File MSSKER.ASM
  3.     include mssdef.h
  4. ; Edit history:
  5. ; 6 Sept 1991 version 3.11
  6. ; Last edit 6 Sept 1991
  7. ;****************************** Version 3.10 ***************************** 
  8. ; KERMIT, Celtic for "free" 
  9. ;
  10. ; The name "Kermit" is a registered trade mark of Henson Associates, Inc.,
  11. ; used by permission.
  12. ;
  13. ;    MS-DOS Kermit Program Version 3.11, 6 Sept 1991
  14. ;    MS-DOS Kermit Program Version 3.10, 2 March 1991
  15. ;    MS-DOS Kermit Program Version 3.02, development for 3.10, 1990-91
  16. ;    MS-DOS Kermit Program Version 3.01, 20 March 1990
  17. ;    MS-DOS Kermit Program Version 3.00, 16 Jan 1990 
  18. ;    Kermit-MS Program Version 2.32, 11 Dec 1988 
  19. ;    Kermit-MS Program Version 2.31, 1 July 1988
  20. ;       Kermit-MS Program Version 2.30, 1 Jan 1988
  21. ;    Kermit-MS Program Version 2.29, 26 May 1986, plus later revisions.
  22. ;       Kermit-MS Program Version 2.27, December 6,1984
  23. ;       Kermit-MS Program Version 2.26, July 27, 1984
  24. ;       PC-Kermit Program Version 1.20, November 4, 1983
  25. ;       PC-Kermit Program Version 1.0, 1982
  26. ;       Based on the Columbia University KERMIT Protocol.
  27. ;       Copyright (C) 1982,1991, Trustees of Columbia University in the
  28. ;       City of New York.  Permission is granted to any individual or
  29. ;       institution to use, copy, or redistribute this software as long as
  30. ;       it is not sold for profit and this copyright notice is retained.
  31. ;
  32. ;       Original Authors (versions 1.0 through 2.28):
  33. ;         Daphne Tzoar, Jeff Damens
  34. ;         Columbia University Center for Computing Activities
  35. ;         612 West 115th Street
  36. ;         New York, NY  10025
  37. ;
  38. ;       Present author (version 2.29, 2.30, 2.31, 2.32, 3.00, 3.01, 3.02,
  39. ;            3.10, 3.11):
  40. ;         Joe R. Doupnik
  41. ;      Dept of EE, and CASS
  42. ;      Utah State University
  43. ;      Logan, UT  84322, USA
  44. ;      E-Mail: JRD@CC.USU.EDU (Internet), JRD@USU (BITNET)
  45. ; Special thanks to Christine Gianone, Frank da Cruz, Bill Catchings, 
  46. ; Bernie Eiben, Vace Kundakci, Terry Kennedy, Jack Bryans, and many many
  47. ; others for their help and contributions.
  48.  
  49.     public    dosnum, curdsk, fpush, isfile, sbrk, crun, errlev
  50.     public    takrd, takadr, taklev, filtst, maxtry, dskspace, thsep, tdfmt
  51.     public    lclsusp, lclrest, lclexit, cwdir, kstatus, verident, cdsr
  52.     public    spath, patched, oldtak, getenv, psp, dosctty, patchid
  53.  
  54.     public    tcptos
  55.  
  56. env    equ    2CH            ; environment address in psp
  57. cline    equ    80H            ; offset in psp of command line
  58. braceop    equ    7bh            ; opening curly brace
  59. bracecl    equ    7dh            ; closing curly brace
  60.  
  61. _STACK    SEGMENT                ; our stack
  62.     dw    1500 dup (0)        ; for TCP code
  63.     dw    200 dup(0)        ; for main Kermit code
  64. msfinal    label    word            ; top of stack
  65. _STACK    ENDS
  66.  
  67. data   segment
  68.     extrn    buff:byte, comand:byte, flags:byte, trans:byte,    prmptr:word
  69.     extrn    machnam:byte, decbuf:byte, rstate:byte, sstate:byte
  70.     extrn    mcctab:byte
  71.  
  72. verident label    byte
  73.     verdef
  74.     db    ' patch level'
  75. patchid    db    ' 0 $'
  76. copyright db    cr,lf
  77.     db    'Copyright (C) Trustees of Columbia University 1982, 1991.'
  78.     db    cr,lf,'$'
  79. hlpmsg    db     cr,lf,'Type ? or HELP for help',cr,lf,'$'
  80. crlf    db      cr,lf,'$'
  81. ermes1    db    cr,lf,'?More parameters are needed$'
  82. ermes2    db    cr,lf,'?Unable to initialize memory$'
  83. ermes3  db      cr,lf,'?Command canceled$'
  84. ermes4    db    '?Unable to change directory',0            ; asciiz
  85. ermes5    db    cr,lf,'?Unable to complete initialization process$'
  86. ermes6    db    cr,lf,'Ignoring patch file MSKERMIT.PCH. '
  87.     db    'Version number mismatch.',cr,lf,'$'
  88. ermes7    db    cr,lf,'Patch file MSKERMIT.PCH was not found',cr,lf,'$'
  89. ermes8    db    cr,lf,'Fatal error in MSKERMIT.PCH! Please remove PATCH '
  90.     db    'command.',cr,lf,'$'
  91. erms30    db    cr,lf,'?Passed maximum nesting level for TAKE command$'
  92. erms31    db    cr,lf,'?Cannot find Take-file: $'
  93. erms34    db    cr,lf,'This program requires DOS 2.0 or above$'
  94. erms37    db    cr,lf,'?Unable to execute program$'
  95. badnam    db    cr,lf,'?No such file(s)$'
  96. filmsg    db    ' Filename$'
  97. dskmsg    db    ' disk drive letter or Return$'
  98. pthmsg    db    ' Name of new working directory and/or disk$'
  99. runmsg    db    ' program name and command line$'
  100. tophlp    db    cr,lf
  101.     db    '  Ask, Askq (read keybd to variable) '
  102.     db    '  Open Read/Write/Append file  scripts'
  103.     db    cr,lf
  104.     db    '  Bye      (logout remote server)    '
  105.     db    '  Output text     (for scripts)'
  106.     db    cr,lf
  107.     db      '  C or Connect  (become a terminal)  '
  108.     db    '  Pause [seconds] (for scripts)'
  109.     db    cr,lf
  110.     db    '  Clear    (clear serial port buffer)'
  111.     db    '  Pop, End (exit current macro/Take file)'
  112.     db    cr,lf
  113.     db    '  Close    (logging and script file) '
  114.     db    '  Push     (go to DOS, keep Kermit)'
  115.     db    cr,lf
  116.     db    '  CLS (clear screen at command level)'
  117.         db      '  Quit     (leave Kermit)'
  118.     db    cr,lf
  119.     db    '  CWD or CD  (change dir &/or disk)  '
  120.         db      '  R or Receive  (opt local filename)'
  121.     db    cr,lf
  122.     db    '  Define/Assign   (a command macro)  '
  123.     db    '  Read (line from a file to variable)'
  124.     db    cr,lf
  125.     db    '  Delete   (a file)                  '
  126.     db    '  Reinput  (script Input, reread buffer)'
  127.     db    cr,lf
  128.     db    '  Directory                          '
  129.     db    '  Remote   (prefix for commands)'
  130.     db    cr,lf
  131.     db    '  Disable  (selected server commands)'
  132.     db    '  Replay   (file through term emulator)'
  133.     db    cr,lf
  134.     db    '  Do       (a macro)                 '
  135.     db    '  Run      (a program)'
  136.     db    cr,lf
  137.     db    '  Echo text (show line on screen)    '
  138.         db      '  S or Send  local file   new name'
  139.     db    cr,lf         
  140.     db    '  Enable   (selected server commands)'
  141.     db    '  Server [timeout] (become a server)'
  142.     db    cr,lf
  143.     db      '  EXIT     (leave Kermit)            '
  144.         db      '  Set      (most things)'
  145.     db    cr,lf
  146.     db    '  Finish   (to remote server)        '
  147.     db    '  Show     (most things)'
  148.     db    cr,lf
  149.     db    '  Get      (remote file opt new name)'
  150.     db    '  Space    (free on current disk)'
  151.     db    cr,lf
  152.     db    '  Goto    (label, Take file or Macro)'
  153.         db      '  Status   (show main conditions)'
  154.     db    cr,lf
  155.     db    '  Hangup   (drop DTR, hang up phone) '
  156.     db    '  Stop     (exit all Take files & macros)'
  157.     db    cr,lf
  158.     db    '  If [not] <condition> <command>     '
  159.     db    '  Take     (do a command file)'
  160.     db    cr,lf
  161.     db    '  I or Input [timeout] text (scripts)'
  162.     db    '  Transmit filespec [prompt] (raw upload)'
  163.     db    cr,lf
  164.     db    '  Log (Packet, Session, Transaction) '
  165.     db    '  Type     (a file)'
  166.     db    cr,lf
  167.     db    '  Logout   (remote server)           '
  168.     db    '  Wait [timeout] on modem \cd \cts \dsr'
  169.     db    cr,lf
  170.     db    '  Mail     (file to host Mailer)     '
  171.     db    '  Write  FILE or log file   text'
  172.     db    '$'
  173.  
  174. data    ends
  175.  
  176. data1    segment
  177. qckhlp    db cr,lf
  178.     db '                    Introduction to MS-DOS Kermit',cr,lf
  179.     db 'o An MS-Kermit command is a line of words separated by spaces and'
  180.     db ' ending with',cr,lf,'  a carriage return <the Enter key>.'
  181.     db '  Example: SET SPEED 2400<Enter>',cr,lf
  182.     db 'o Most words can be abbreviated and can be completed by pressing'
  183.     db ' the Esc key.',cr,lf
  184.     db '  Example: SET SPE 24<Enter>  or even  SET SPE<Esc> 24<Esc>'
  185.     db '<Enter>',cr,lf
  186.     db 'o Help (detailed, specific): press the "?" key where a word would'
  187.     db ' appear.',cr,lf
  188.     db 'o Edit lines using the Backspace key to delete characters,'
  189.     db ' Control-W to delete',cr,lf
  190.     db '  words, and Control-U to delete the line.  Control-C cancels the'
  191.     db ' command.',cr,lf
  192.     db 'o Frequently used MS-Kermit commands:',cr,lf
  193.     db '  EXIT           Leave the Kermit program. QUIT does the same'
  194.     db ' thing.',cr,lf
  195.     db '  SET            PORT, PARITY, SPEED, TERMINAL and many other'
  196.     db ' parameters.',cr,lf
  197.     db '  SHOW or STATUS Display groups of important parameters.'
  198.     db ' SHOW ? for categories.',cr,lf,lf
  199.     db '  CONNECT        Establish a terminal connection to a remote'
  200.     db ' system or a modem.',cr,lf
  201.     db '  Control-$'
  202. qckhlp1    db ' C    (Control-$'
  203. qckhlp2    db '  followed by "C")  Return to MS-Kermit> prompt.',cr,lf,lf
  204.     db '  SEND filename  Send the file(s) to Kermit on the other'
  205.     db ' computer.',cr,lf
  206.     db '  RECEIVE        Receive file(s), SEND them from Kermit on the'
  207.     db ' other computer.',cr,lf
  208.     db '  GET filename   Ask the remote Kermit server to send the file(s)'
  209.     db ' to us.',cr,lf
  210.     db '  FINISH         Shut down remote Kermit but stay logged into'
  211.     db ' remote system.',cr,lf
  212.     db '  BYE            FINISH and logout of remote system and exit'
  213.     db ' local Kermit.',cr,lf
  214.     db 'o Common startup sequence: SET SPEED 9600, CONNECT, login, start'
  215.     db ' remote Kermit,',cr,lf
  216.     db '  put it into Server mode, escape back with Control-$'
  217. qckhlp3    db ' C, transfer'
  218.     db ' files with',cr,lf
  219.     db '  SEND x.txt, GET b.txt, BYE. Read more about it in "Using MS-DOS'
  220.     db ' Kermit".'
  221.     db cr,lf
  222.     db ' - more -  Press the space bar for a functional summary of '
  223.     db 'Kermit commands. $'
  224.  
  225. qckhlp5    db    cr,lf,lf,lf,' MS-DOS Kermit commands, a functional summary:'
  226.     db    cr,lf
  227.     db    cr,lf,' Local file management:         '
  228.     db    'Kermit program management:'
  229.     db    cr,lf,'   DIR    (list files)          '
  230.     db    '  EXIT     (from Kermit, return to DOS)'
  231.     db    cr,lf,'   CD     (change directory)    '
  232.     db    '  QUIT     (same as EXIT)'
  233.     db    cr,lf,'   DELETE (delete files)        '      
  234.     db    '  TAKE     (execute Kermit commands from file)'
  235.     db    cr,lf,'   RUN    (a DOS command)       '
  236.     db    '  CLS      (clear screen)'
  237.     db    cr,lf,'   TYPE   (display a file)      '
  238.     db    '  PUSH     (enter DOS, EXIT returns to Kermit)'
  239.     db    cr,lf,'   SPACE  (show disk space)     '
  240.     db    '  Ctrl-C   (interrupt a command)'
  241.     db    cr,lf
  242.     db    cr,lf,' Communication settings:        '
  243.     db    'Terminal emulation:'
  244.     db    cr,lf,'   SET PORT, SET SPEED          '
  245.     db    '  CONNECT  (begin terminal emulation)'
  246.     db    cr,lf,'   SET PARITY                   '
  247.     db    '  HANGUP   (close connection)'
  248.     db    cr,lf,'   SET FLOW-CONTROL             '
  249.     db    '  Alt-X    (return to MS-Kermit> prompt)'
  250.     db    cr,lf,'   SET LOCAL-ECHO               '
  251.     db    '  SET KEY  (key mapping)'
  252.     db    cr,lf,'   SET ? to see others          '
  253.     db    '  SET TERMINAL TYPE, BYTESIZE, other parameters'
  254.     db    cr,lf,'   SHOW COMMUNICATIONS, MODEM   '
  255.     db    '  SHOW TERMINAL, SHOW KEY'
  256.     db    cr,lf,lf,' - more -$'
  257. qckhlp6    db    cr,'          '
  258.     db    cr,lf,' File transfer settings:        '
  259.     db    cr,lf,'   SET FILE CHARACTER-SET name  '  
  260.     db    '  SET TRANSFER CHARACTER-SET'
  261.     db    cr,lf,'   SET FILE TYPE TEXT, BINARY   '  
  262.     db    '  SET SEND or RECEIVE parameters'
  263.     db    cr,lf,'   SET FILE ? to see others     '  
  264.     db    '  SET WINDOWS (sliding windows)'
  265.     db    cr,lf,'   SHOW FILE                    '  
  266.     db    '  SHOW PROTOCOL, SHOW STATISTICS'
  267.     db    cr,lf
  268.     db    cr,lf,' Kermit file transfer:           '
  269.     db    'ASCII file transfer:'
  270.     db    cr,lf,'   SEND files (to RECEIVE)      '
  271.     db    '  LOG SESSION, CLOSE SESSION (download)'
  272.     db    cr,lf,'   RECEIVE    (from SEND)       '
  273.     db    '  TRANSMIT (upload)'
  274.     db    cr,lf,'   MAIL files (to RECEIVE)      '
  275.     db    '  SET TRANSMIT parameters'
  276.     db    cr,lf,lf,' - more - $'
  277. qckhlp7    db    cr,'          '
  278.     db    cr,lf,' Using a Kermit server:         '
  279.     db    'Being a kermit server:'
  280.     db    cr,lf,'   GET files    (from server)   '
  281.     db    '  SET SERVER TIMEOUT or LOGIN'
  282.     db    cr,lf,'   SEND or MAIL   (to server)   '
  283.     db    '  ENABLE or DISABLE features'
  284.     db    cr,lf,'   REMOTE command (to server)   '
  285.     db    '  SERVER'
  286.     db    cr,lf,'   FINISH, LOGOUT, BYE          '
  287.     db    '  SHOW SERVER'
  288.     db    cr,lf
  289.     db    cr,lf,' Script programming commands:   '
  290.     db    cr,lf,'   INPUT, REINPUT secs text     '
  291.     db    '  :label, GOTO label'
  292.     db    cr,lf,'   OUTPUT text                  '
  293.     db    '  IF [ NOT ] condition command'
  294.     db    cr,lf,'   ASK or ASKQ variable prompt  '
  295.     db    '  OPEN READ (or WRITE or APPEND) file'
  296.     db    cr,lf,'   DEFINE variable or macro     '
  297.     db    '  READ variable-name'
  298.     db    cr,lf,'   ASSIGN variable or macro     '
  299.     db    '  WRITE file-designator text'
  300.     db    cr,lf,'   [ DO ] macro arguments       '
  301.     db    '  CLOSE READ or WRITE file or logfile'
  302.     db    cr,lf,'   ECHO text                    '
  303.     db    '  END or POP from macro or file'
  304.     db    cr,lf,'   PAUSE time                   '
  305.     db    '  STOP all macros and command files'
  306.     db    cr,lf,'   WAIT time modem-signals      '
  307.     db    '  WRITE file-designator text'
  308.     db    cr,lf,'   SHOW SCRIPTS, SHOW MACROS    '
  309.     db    '  SHOW VARIABLES'
  310.     db    cr,lf,lf
  311.     db ' Use "?" within comands for help on what fits that word.',lf,'$'
  312. data1    ends
  313.  
  314. data    segment
  315.  
  316. comtab  db    64            ; COMND tables
  317.     mkeyw    'Asg',assign        ; synonym
  318.     mkeyw    'Ask',ask
  319.     mkeyw    'Askq',askq
  320.     mkeyw    'Assign',assign
  321.     mkeyw    'Bye',bye
  322.     mkeyw    'C',telnet
  323.     mkeyw    'CD',cwdir
  324.     mkeyw    'Clear',scclr
  325.     mkeyw    'Close',clscpt
  326.     mkeyw    'Comment',comnt
  327.     mkeyw    'Connect',telnet
  328.     mkeyw    'CLS',cls
  329.     mkeyw    'CWD',cwdir
  330.     mkeyw    'Define',dodef
  331.     mkeyw    'Delete',delete
  332.     mkeyw    'Directory',direct
  333.     mkeyw    'Disable',srvdsa
  334.     mkeyw    'Do',docom
  335.     mkeyw    'Echo',scecho
  336.     mkeyw    'Enable',srvena
  337.     mkeyw    'End',popcmd
  338.     mkeyw    'Exit',exit
  339.     mkeyw    'Finish',finish
  340.     mkeyw    'Get',get
  341.     mkeyw    'goto',goto
  342.     mkeyw    'H',help
  343.     mkeyw    'Hangup',dtrlow
  344.     mkeyw    'Help',help
  345.     mkeyw    'If',ifcmd
  346.     mkeyw    'I',scinp
  347.     mkeyw    'Input',scinp
  348. ;;;    mkeyw    'Load',load
  349.     mkeyw    'Log',setcpt
  350.     mkeyw    'Logout',logout
  351.     mkeyw    'Mail',mail
  352.     mkeyw    'Open',vfopen
  353.     mkeyw    'Output',scout
  354.     mkeyw    'Pause',scpau
  355.     mkeyw    'Pop',popcmd
  356.     mkeyw    'Push',dopush
  357.     mkeyw    'Quit',exit
  358.     mkeyw    'R',read
  359.     mkeyw    'Read',vfread
  360.     mkeyw    'Receive',read
  361.     mkeyw    'Reinput',screinp
  362.     mkeyw    'Remote',remote
  363.     mkeyw    'Replay',replay
  364.     mkeyw    'Run',run
  365.     mkeyw    'S',send
  366.     mkeyw    'Send',send
  367.     mkeyw    'Server',server
  368.     mkeyw    'Set',setcom
  369.     mkeyw    'Show',showcmd
  370.     mkeyw    'Space',chkdsk
  371.     mkeyw    'Status',status
  372.     mkeyw    'Stay',stay
  373.     mkeyw    'Stop',takeqit
  374.     mkeyw    'Take',take
  375.     mkeyw    'Transmit',scxmit
  376.     mkeyw    'Type',typec
  377.     mkeyw    'Version',prvers
  378.     mkeyw    'Wait',scwait
  379.     mkeyw    'Write',write
  380.     mkeyw    ':',comnt        ; script labels, do not react
  381.     mkeyw    'Patch',patch
  382.  
  383. shotab    db    14            ; SHOW keyword
  384.     mkeyw    'Communications',shcom
  385.     mkeyw    'File',shfile
  386.     mkeyw    'Key',shokey
  387.     mkeyw    'Logging',shlog
  388.     mkeyw    'Macros',shomac
  389.     mkeyw    'Memory',shmem
  390.     mkeyw    'Modem',shomodem
  391.     mkeyw    'Protocol',shpro
  392.     mkeyw    'Scripts',shscpt
  393.     mkeyw    'Server',shserv
  394.     mkeyw    'Statistics',shosta
  395.     mkeyw    'Terminal',shterm
  396.     mkeyw    'Translation',shorx
  397.     mkeyw    'Variables',shovar
  398.                     ; Kermit initing from Environment
  399. nulprmpt db    0            ; null prompt
  400. initab    db    6            ; Environment phrase dispatch table
  401.     mkeyw    'INPUT-buffer-length',setinpbuf ; Script INPUT buffer length
  402.     mkeyw    'Rollback',setrollb    ; number of Terminal rollback screens
  403.     mkeyw    'COM1',com1port
  404.     mkeyw    'COM2',com2port
  405.     mkeyw    'COM3',com3port
  406.     mkeyw    'COM4',com4port
  407. patched    db    1        ; 1 = enable patching; 0 = disable or done
  408.  
  409.     even
  410. lclsusp    dw    0        ; address of routine to call when going to DOS
  411. lclrest    dw    0        ; address of routine to call when returning
  412. lclexit    dw    0        ; address of routine to call when exiting
  413. tcptos    dw    0        ; top of stack for TCP code
  414. ssave    dd    0        ; Original SS:SP when doing Command.com
  415. in3ad    dw    0,0        ; Original break interrupt addresses
  416. ceadr    dd    0        ; DOS Critical Error interrupt address
  417. orgcbrk    db    0        ; original Control-Break Check state
  418. psp    dw    0        ; segment of Program Segment Prefix
  419. exearg    dw    0        ; segment addr of environment (filled in below)
  420.     dd    0        ; ptr to cmd line (filled in below)
  421.     dw    5ch,0,6ch,0    ; our def fcb's; segment filled in later
  422. dosnum    dw    0        ; dos version number, major=low, minor=high
  423. dosctty    db    0        ; !=0 if DOS attempts using our comms line
  424. curdsk    db    0        ; Current disk
  425. origd    db    0        ; Original disk
  426. orgdir    db    64 dup (0)    ; original directory on original disk
  427. taklev    db    0        ; Take levels
  428. oldtak    db    0        ; Take level at start of command parse
  429. takadr    dw    takstr-(size takinfo) ; Pointer into structure
  430. takstr    db    (size takinfo) * maxtak dup(?)
  431. filtst    filest    <>        ; file structure for procedure isfile
  432. maxtry    db    defmxtry    ; Retry limit for data packet send/rcv
  433. ininm2    db    'MSKERMIT.INI',0 ; init file name for 2.0
  434. ptchnam    db    'MSKERMIT.PCH',0 ; patch file name
  435. delcmd    db    ' del ',0    ; delete command
  436. dircmd    db    ' dir ',0    ; directory command
  437. typcmd    db    ' type ',0    ; type command
  438. kerenv    db    'KERMIT=',0,0    ; Kermit= environment variable, + 2 nulls
  439. pthnam    db    'PATH='        ; Path environment variable
  440. pthlen    equ    $-pthnam    ;  length of that string
  441. pthadr    dw    0        ; offset of PATH= string
  442.  
  443. slashc    db    ' /c '        ; slashc Must directly preceed tmpbuf
  444. tmpbuf    db    128 dup (0)    ; temp space for file names and comments
  445. cmspnam    db    'COMSPEC='    ; Environment variable
  446. cmsplen    equ    $-cmspnam
  447. cmspbuf    db    '\command.com',30 dup (0) ; default name plus additional space
  448. shellnam db    'SHELL='    ; Environment variable
  449. shellen    equ    $-shellnam
  450. shellbuf db    40 dup (0)    ; buffer for name
  451. eexit    db    cr,'exit',cr
  452. leexit    equ    $-eexit
  453. onexit    db    7,0,'ON_EXIT'    ; <length>on_exit macro name
  454. onexlen    equ    $-onexit-2    ; length of name
  455. mfmsg    db    '?Not enough memory to run Kermit$'
  456. mf7msg    db    '?Attempted to allocate a corrupted memory area$'
  457. spcmsg    db    ' bytes available on drive '
  458. spcmsg1    db    ' :',cr,lf,0
  459. spcmsg2    db    cr,lf,' Drive '
  460. spcmsg3    db    ' : is not ready',0
  461. errlev    db    0        ; DOS errorlevel to be returned
  462. kstatus    dw    0        ; command execution status (0 = success)
  463. thsep    db    0        ; thousands separator
  464. tdfmt    db    0        ; date/time format code
  465. totpar    dw    0
  466. temp    dw    0
  467.  
  468. segstr    db    'ABCDEFG'    ; segment "names" for patcher
  469. lsegstr    equ    $-segstr
  470.     even
  471. segtab    dw    code        ; segment values for patcher
  472.     dw    code1
  473.     dw    code2
  474.     dw    data
  475.     dw    data1
  476.     dw    _TEXT
  477.     dw    dgroup
  478.  
  479. exmacptr dw    offset exmacro,seg exmacro
  480. psetint    dw    offset setint,seg setint
  481. data   ends
  482.  
  483. code    segment
  484.     extrn    logout:near, mail:near, load:near, shovar:near
  485.     extrn    bye:near, telnet:near, finish:near, comnd:near, prompt:near
  486.     extrn    read:near, remote:near, send:near, status:near, get:near
  487.     extrn    serrst:near, setcom:near, dtrlow:near, cmblnk:near
  488.     extrn    clscpi:near, clscpt:near, scpini:near, setrollb:near
  489.     extrn    dodef:near, setcpt:near, docom:near, shomodem:near
  490.     extrn    server:near, lclini:near, shokey:near, shomac:near, shosta:near
  491.     extrn    strlen:near, strcpy:near, shserv:near, initibm:near
  492.     extrn    strcat:near, prtasz:near, shorx:near, lnout:near, lnouts:near
  493.     extrn    scout:near,scinp:near,scpau:near,scecho:near,scclr:near
  494.     extrn    scxmit:near, scwait:near, srvdsa:near, srvena:near
  495.     extrn    shcom:near, shlog:near, shpro:near, shterm:near, shscpt:near
  496.     extrn    shfile:near, takopen:near, takclos:near, ask:near, askq:near
  497.     extrn    assign:near, goto:near, screinp:near, ifcmd:near, write:near
  498.     extrn    setinpbuf:near, shmem:near, replay:near, atoi:near
  499.     extrn    katoi:near, com1port:near, com2port:near, com3port:near,
  500.     extrn    com4port:near, popcmd:near, mprompt:near, locate:near
  501.     extrn    vfopen:near, vfread:near
  502.  
  503.         assume  cs:code, ds:data, ss:_stack, es:nothing
  504.  
  505. START    PROC    FAR
  506.     mov    ax,data            ; initialize DS
  507.         mov    ds,ax
  508.     mov    psp,es            ; remember psp address
  509.     mov    ah,dosver        ; get DOS version number (word)
  510.     int    dos
  511.     xchg    ah,al            ; major version to ah
  512.     mov    dosnum,ax        ; remember dos version
  513.     cmp    ax,200h            ; earlier than DOS 2.0?
  514.     jge    start1            ; ge = no
  515.     mov    ah,prstr
  516.     mov    dx,offset erms34    ; complain
  517.     int    dos
  518.     push    psp            ; set up exit for DOS 1
  519.     xor    ax,ax            ; and the IP
  520.     push    ax            ; make return addr of psp:0 for DOS 1
  521.     ret                ; and return far to exit now
  522. start1:
  523.     call    memini            ; initialize our memory usage
  524.     mov    ah,setdma        ; set disk transfer address
  525.     mov    dx,offset buff
  526.     int    dos
  527.  
  528.     call    dword ptr psetint    ; ^C, DOS critical error interrupts
  529.     mov    ah,gcurdsk        ; get current disk
  530.     int    dos
  531.     inc    al            ; make 1 == A (not zero)
  532.     mov    curdsk,al
  533.     mov    origd,al        ; remember original disk we started on
  534.     mov    si,offset orgdir     ; place for directory path w/o drive code
  535.     add    al,'A'-1        ; make al alphabetic disk drive again
  536.     mov    [si],al            ; put it into original path descriptor
  537.     inc    si
  538.     mov    byte ptr [si],':'    ; add drive specifier too
  539.     inc    si
  540.     mov    byte ptr [si],'\'    ; add root indicator as well
  541.     inc    si
  542.     mov    ah,gcd            ; get current directory (path really)
  543.     xor    dl,dl            ; use current drive
  544.     int    dos
  545.     call    getpath            ; get the path from the environment
  546.     call    gettsep            ; get thousands separator, t/date code
  547.     mov    ah,gswitch
  548.     xor    al,al            ; pick up switch character
  549.     int    dos
  550.     mov    slashc+1,dl
  551.     and    maxtry,3fh        ; limit # packet retries
  552.     call    getcsp            ; get comspec from environment
  553.     call    getssp            ; get shellspec from environment
  554.     call    getparm            ; read "KERMIT=" Environment line
  555.     jc    start1b            ; c = fatal error
  556.     xor    cl,cl            ; counter, starts at 0
  557. start1a:mov    bx,offset kerenv+6    ; append "<digit>="  to "KERMIT"
  558.     mov    [bx],cl            ; binary digit
  559.     inc    cl
  560.     add    byte ptr [bx],'0'    ; to ascii
  561.     mov    byte ptr [bx+1],'='    ; append equals sign
  562.     call    getparm            ; read "KERMITn=" Environment line
  563.     jc    start1b            ; c = fatal error
  564.     cmp    cl,9            ; done all digits?
  565.     jbe    start1a            ; be = no
  566.                     ;
  567.     call    scpini            ; initialize script routines
  568.     jc    start1b            ; c = fatal error
  569.     call    lclini            ; do local initialization
  570.     cmp    flags.extflg,0        ; exit now?
  571.     je    start2            ; e = no
  572. start1b:mov    ah,prstr        ; announce our premature exit
  573.     mov    dx,offset ermes5    ; can't complete initialization
  574.     int    dos
  575.     jmp    krmend            ; quit immediately
  576. start2:    mov    word ptr comand.cmrprs,offset krmend ; offset of reparse addr
  577.     mov    ax,cs            ; our current code segment
  578.     mov    word ptr comand.cmrprs+2,ax ; segment of reparse address
  579.     mov    comand.cmostp,sp    ; save for reparse too
  580.     call    gcmdlin            ; read command line
  581.     cmp    taklev,0        ; in a Take file?
  582.     jne    start3            ; ne = yes, skip help msg
  583.     mov    ah,prstr
  584.     mov    dx,offset machnam    ; display machine name
  585.     int    dos
  586.         mov    dx,offset verident    ; display version header
  587.         int    dos
  588.     mov    dx,offset copyright    ; display copyright notice
  589.     int    dos
  590.     mov    dx,offset hlpmsg
  591.     int    dos
  592. start3:    call    serrst            ; reset serial port (if active)
  593.     call    initibm            ; define IBM macro
  594.     call    rdinit            ; read kermit init file
  595.  
  596.  ; This is the main KERMIT loop.  It prompts for and gets the users commands
  597.  
  598. kermit:    mov    ax,ds
  599.     mov    es,ax            ; convenient safety measure
  600.     mov    dx,prmptr        ; get prompt string address
  601.     call    mprompt              ; set master reparse address to here
  602.     cmp    flags.cxzflg,'C'    ; did someone want out?
  603.     jne    kermt9            ; ne = no
  604. kermt8:    cmp    taklev,0        ; are we in a Take file?
  605.     je    kermt9            ; e = no, ignore the signal
  606.     call    takclos            ; close take file, release buffer
  607.     jmp    short kermt8        ; close any other take files
  608. kermt9:    mov    flags.cxzflg,0        ; reset each time
  609.     and    flags.remflg,not dserver ; turn off server mode bit
  610.     cmp    dosctty,0        ; is DOS using our comms line?
  611.     je    kermt1            ; e = no
  612.     and    flags.remflg,not(dquiet+dregular+dserial)
  613.     or    flags.remflg,dquiet    ; set display to quiet mode
  614.     call    serrst            ; close port so CTTY can run
  615. kermt1:    mov    dx,offset comtab
  616.     mov    bx,offset tophlp
  617.     cmp    flags.extflg,0        ; exit flag set?
  618.     jne    krmend            ; ne = yes, jump to KRMEND
  619.     mov    comand.cmcr,1        ; allow bare CR's
  620.         mov    ah,cmkey
  621.     mov    comand.impdo,1        ; allow implied "DO macro"
  622.     call    comnd
  623.     jc    kermt3            ; c = failure
  624.     mov    comand.impdo,0        ; only on initial keyword, not here
  625.     mov    comand.cmcr,0        ; no more bare CR's
  626.     call    bx                  ; call the routine returned in BX
  627.     jc    kermt3            ; c = failure
  628.     cmp    flags.extflg,0        ; exit flag set?
  629.     jne    krmend            ; ne = yes, jump to KRMEND
  630.     jmp    short kermt5        ; do idle loop cleanup
  631.  
  632. kermt3:    cmp    flags.cxzflg,'C'    ; got here via Control-C?
  633.     jne    kermt7            ; ne = no
  634.     cmp    flags.extflg,0        ; exit flag set?
  635.     jne    kermt5            ; ne = yes, skip msg, do cleanup
  636.     mov    dx,offset ermes3    ; say command not executed
  637.     mov    ah,prstr        ; print    the error message in dx
  638.     int    dos
  639. kermt5:    cmp    flags.cxzflg,'C'    ; user Control-C abort?
  640.     jne    kermt7            ; ne = no, do normal operations
  641.     cmp    taklev,0        ; in a Take file?
  642.     je    kermt7            ; e = no        
  643.     call    takclos            ; close take file, release buffer
  644.     jmp    short kermt5        ; close any other take files
  645. kermt7:    cmp    flags.extflg,0        ; exit flag set?
  646.     jne    krmend            ; ne = yes, exit
  647.     jmp    kermit            ; e = no, get next command
  648.  
  649. krmend:cmp    taklev,0        ; in a Take file?
  650.     je    krmend2a        ; e = no        
  651.     call    takclos            ; close take file, release buffer
  652.     jmp    short krmend        ; close any other take files
  653. krmend2a:call    dword ptr exmacptr    ; find on_exit macro
  654.     jc    krmend2c        ; c = not found
  655.                     ; perform ON_EXIT macro
  656. krmend2b:cmp    taklev,0        ; finished with macros?
  657.     je    krmend2c        ; e = yes
  658.     mov    dx,prmptr        ; get prompt string address
  659.     call    mprompt              ; set master reparse address to here
  660.     mov    flags.cxzflg,0        ; reset each time
  661.     and    flags.remflg,not dserver ; turn off server mode bit
  662.     mov    dx,offset comtab    ; keyword table
  663.     xor    bx,bx            ; no help
  664.         mov    ah,cmkey
  665.     mov    comand.impdo,1        ; allow implied "DO macro"
  666.     mov    comand.cmcr,1        ; allow bare CR's
  667.     call    comnd
  668.     jc    krmend2c        ; c = failure
  669.     mov    comand.impdo,0        ; only on initial keyword, not here
  670.     call    bx            ; call the routine returned in BX
  671.     jnc    krmend2b        ; nc = success, keep doing commands
  672. krmend2c:                ; end of ON_EXIT macro processing
  673.     call    serrst            ; just in case the port wasn't reset
  674.     call    clscpi            ; close log files
  675.     mov    bx,lclexit        ; addr of sys dependent exit routine
  676.     or    bx,bx            ; sys dependent routines want service?
  677.     jz    krmend3            ; z = no
  678.     call    bx            ; call it
  679. krmend3:mov    dl,origd        ; original disk drive
  680.     dec    dl            ; want A == 0
  681.     mov    ah,seldsk        ; reset original disk just in case
  682.     int    dos
  683.     mov    dx,offset orgdir    ; restore original directory
  684.     mov    ah,chdir
  685.     int    dos
  686.     push    ds            ; save ds around these DOS calls
  687.     mov    ax,cs            ; compose full address of ^C routine
  688.     mov    ds,ax            ; segment is the code segment
  689.     mov    dx,offset in3ad        ; restore Control-C interrupt vector
  690.     mov    al,23H            ; interrupt 23H
  691.     mov    ah,25H            ; set interrupt vector
  692.     int    dos            ; ah, that's better
  693.     mov    dx,offset ceadr        ; DOS's Critical Error handler
  694.     mov    al,24h            ; interrupt 24h
  695.     mov    ah,25h            ; do replacement (put it back)
  696.     int    dos
  697.     pop    ds
  698.     call    cbrestore        ; restore state of Control-Break Chk
  699.     mov    ah,4cH            ; terminate process
  700.     mov    al,errlev        ; return error level
  701.     int    dos
  702.     ret
  703. START    ENDP
  704.  
  705. ; This is the 'EXIT' command.  It leaves KERMIT and returns to DOS
  706.  
  707. EXIT    PROC    NEAR
  708.     mov    ah,cmeol
  709.     call    comnd            ; get a confirm
  710.     jc    exit1            ; c = failure
  711.     mov    flags.extflg,1        ; set the exit-Kermit flag
  712. exit1:    ret
  713. EXIT    ENDP
  714. code    ends
  715.  
  716. code1    segment
  717.     assume    cs:code1
  718. exmacro    proc    far            ; perform on_exit() macro
  719.     push    bx
  720.     push    cx
  721.     push    si
  722.     mov    bx,offset mcctab    ; table of macro names
  723.     mov    cl,[bx]            ; number of names in table
  724.     xor    ch,ch
  725.     jcxz    exmacx            ; z = empty table, do nothing
  726.     inc    bx            ; point to length of first name
  727. exmac2:    mov    ax,[bx]            ; length of this name
  728.     cmp    ax,onexlen        ; length same as desired keyword?
  729.     jne    exmac3            ; ne = no, search again
  730.     mov    si,bx
  731.     add    si,2            ; point at first char of name
  732.     push    cx            ; save name counter
  733.     push    di            ; save reg
  734.     mov    cx,onexlen        ; length of name
  735.     mov    di,offset onexit+2    ; point at desired macro name text
  736.     push    es            ; save reg
  737.     push    ds
  738.     pop    es            ; make es use data segment
  739.     cld
  740.     repe    cmpsb            ; match strings
  741.     pop    es            ; need current si below
  742.     pop    cx
  743.     pop    di            ; recover saved regs
  744.     jne    exmac3            ; ne = no match
  745.     mov    onexit+2,0        ; change name to be invisible
  746.     mov    byte ptr [bx+2],0    ; change macro table name too
  747.     jmp    short exmac4        ; e = matched
  748. exmac3:    add    bx,ax            ; step to next name, add name length
  749.     add    bx,4            ; + count and def word ptr
  750.     loop    exmac2            ; try next name
  751. exmacx:    pop    si            ; no macro, fail
  752.     pop    cx
  753.     pop    bx
  754.     stc                ; say failure
  755.     ret
  756.  
  757. exmac4:    cmp    taklev,maxtak        ; room in Take level?
  758.     jge    exmacx            ; ge = no, exit with no action
  759.     inc    taklev            ; increment take level
  760.     add    takadr,size takinfo    ; make a new Take entry/macro
  761.     mov    bx,takadr        ; point to current macro structure
  762.     mov    ax,ds            ; text is in our data seg
  763.     mov    [bx].takbuf,ax        ; seg of definition string struc
  764.     mov    [bx].takptr,offset onexit+2 ; where to read next command char
  765.     mov    [bx].takcnt,onexlen    ; number of chars in definition
  766.     mov    [bx].takargc,0        ; store macro argument count
  767.     mov    [bx].taktyp,0ffh    ; flag as a macro
  768.     pop    si
  769.     pop    cx
  770.     pop    bx
  771.     clc                ; say success
  772.     ret
  773. exmacro    endp
  774. code1    ends
  775.  
  776. code    segment
  777.     assume    cs:code
  778. ; TAKE commands    from a file, and allow a path name
  779. TAKE    PROC    NEAR
  780.     mov    kstatus,kssuc        ; global status, success
  781.     cmp    taklev,maxtak        ; at the limit?
  782.     jl    take1            ; l = no
  783.     mov    ah,prstr
  784.     mov    dx,offset erms30    ; complain
  785.     int    dos
  786.     stc                ; failure
  787.     ret
  788. take1:    mov    dx,offset tmpbuf    ; work buffer
  789.     mov    tmpbuf,0
  790.     mov    bx,offset filmsg    ; Help in case user types "?"
  791.     mov    comand.cmkeep,1        ; keep file open
  792.     mov    ah,cmword        ; get file name
  793.     call    comnd
  794.     jc    take1a            ; c = failure
  795.     mov    ah,cmeol
  796.     call    comnd
  797.     jc    take1a            ; c = failure
  798.     mov    ax,offset tmpbuf    ; point to name again
  799.     cmp    tmpbuf,0        ; empty filespec?
  800.     jne    take2            ; ne = no
  801.     mov    ah,prstr
  802.     mov    dx,offset ermes1    ; say more parameters needed
  803.     int    dos
  804.     stc
  805. take1a:    ret
  806.                     ; TAKE2: enter with ax=filename ptr
  807. TAKE2:    call    spath            ; is it around?
  808.     jc    take3            ; no, go complain
  809.     mov    dx,ax            ; point to name from spath
  810.     mov    ah,open2        ; open file
  811.     xor    al,al            ; 0 = open for reading
  812.     cmp    dosnum,300h        ; at or above DOS 3?
  813.     jb    take2a            ; b = no, so no shared access
  814.     or    al,40h            ; open for reading, deny none
  815. take2a:    int    dos
  816.     jnc    take4            ; nc = opened ok, keep going
  817.     mov    ax,dx            ; recover filename pointer
  818. take3:    push    ax
  819.     mov    ah,prstr
  820.     mov    dx,offset erms31
  821.     int    dos
  822.     pop    ax
  823.     mov    dx,ax            ; asciiz file name
  824.     call    prtasz            ; display it
  825.     mov    kstatus,kstake        ; status, Take failed
  826.     clc                ; we've done all error displays
  827.     ret
  828.                     ; TAKE4: enter with ax=filename ptr
  829. TAKE4:    call    takopen            ; open take buffer in macro space
  830.     jc    take6            ; c = failure
  831.     push    bx
  832.     mov    bx,takadr        ; get current frame ptr
  833.     mov    [bx].takhnd,ax        ; save file handle
  834.     mov    [bx].taktyp,0feh     ; mark as 2.0 file handle
  835.     pop    bx
  836.     cmp    flags.takflg,0        ; echoing Take files?
  837.     je    take5            ; e = no
  838.     mov    ah,prstr
  839.     mov    dx,offset crlf
  840.     int    dos
  841. take5:    call    takrd            ; get a buffer full of data
  842.     clc                ; success
  843. take6:    ret
  844. TAKE    ENDP
  845.  
  846. TAKRD    PROC    NEAR
  847.     push    ax
  848.     push    bx
  849.     push    cx    
  850.     push    dx
  851.     mov    bx,takadr
  852.     cmp    [bx].taktyp,0feh    ; get type of take (file?)
  853.     jne    takrd1            ; ne = no, do not read from disk
  854.     mov    cx,tbufsiz-2        ; # of bytes to read
  855.     mov    ax,[bx].takbuf        ; segment of Take buffer
  856.     push    bx            ; save frame address
  857.     mov    bx,[bx].takhnd        ; file handle is stored here
  858.     push    ds            ; save ds
  859.     mov    ds,ax            ; set ds to Take buffer segment
  860.     mov    dx,2            ; ds:dx = buffer, skip count word
  861.     mov    ah,readf2        ; read file
  862.     int    dos
  863.     pop    ds
  864.     pop    bx            ; restore frame address
  865.     jnc    takrd2            ; nc = successful read
  866. takrd1:    xor    ax,ax            ; error, say zero bytes read
  867. takrd2:    mov    [bx].takcnt,ax        ; number of bytes read
  868.     mov    [bx].takptr,2        ; offset of first new character
  869.     pop    dx
  870.     pop    cx
  871.     pop    bx
  872.     pop    ax
  873.     ret
  874. TAKRD    ENDP
  875.  
  876. ; TAKE-QUIT  (STOP)  Exit all Take files immediately but gracefully
  877.  
  878. TAKEQIT PROC    NEAR
  879.     mov    ah,cmeol
  880.     call    comnd
  881.     jnc    takqit1            ; nc = success
  882.     ret
  883. takqit1:xor    ch,ch
  884.     mov    cl,taklev        ; number of Take levels active
  885.     jcxz    takqit2            ; z = none
  886.     call    takclos            ; close current Take file
  887.     jmp    short takqit1        ; repeat until all are closed
  888. takqit2:clc                ; success
  889.     ret
  890. TAKEQIT    ENDP
  891.  
  892. ; put mskermit.ini onto take stack if it exists.  Just like
  893. ; the take command, except it doesn't read a filename
  894.  
  895. rdinit    proc    near            ; read kermit init file..
  896.     mov    ax,offset ininm2    ; default name to try
  897.     cmp    decbuf,0        ; alternate init file given?
  898.     je    rdini1            ; ne = no
  899.     mov    ax,offset decbuf    ; yes, use it
  900.     call    take2            ; let Take do error msgs
  901.     clc                ; force success
  902.     ret
  903. rdini1:    call    spath            ; is it around?
  904.     jc    rdini2            ; no, ignore file
  905.     mov    dx,ax            ; point to name from spath
  906.     mov    ah,open2        ; open file
  907.     xor    al,al            ; 0 = open for reading
  908.     cmp    dosnum,300h        ; at or above DOS 3?
  909.     jb    rdini1a            ; b = no, so no shared access
  910.     or    al,40h            ; open for reading, deny none
  911. rdini1a:int    dos
  912.     jc    rdini2            ; c = no ini file found, ignore
  913.     call    take4            ; use TAKE command to complete work
  914.     clc                ; ignore errors
  915. rdini2:    ret
  916. rdinit    endp
  917.  
  918. ; Patcher.  Patch file, MSKERMIT.PCH has the following format:
  919.  
  920. ; 301 \Xxxxx    Text to display upon successful patch load
  921. ; ;301 for V3.01.  For xxxx, see below
  922. ; ; optional comment lines may appear anywhere after the 1st
  923. ; ; xxxx in 1st line = total paragraphs in memory image.  Use \X if hex.
  924. ; DS:xxxx xx xx        ; optional comment.  DS (or CS) are case insensitive
  925. ; CS:xxxx xx xx xx    ; locations must be 4 hex chars, contents must be 2
  926. ;
  927. ; The 1st xx is the original value of the 1st byte @seg:offset for comparison.
  928. ; A 00 value says don't compare.  Subsequent xx's are replacement bytes.
  929. ; CS & DS lines may be intermixed.  AS & BS segments may be used when some
  930. ; external module sets words aseg & bseg to a seg-base.
  931. ; This mechanism expects file msscmd.obj to be linked first.
  932.  
  933. PATCH    proc
  934.     mov    ah,cmeol    ; confirm please
  935.     call    comnd
  936.     jc    patch1        ; c = no confirm
  937.     xor    ax,ax
  938.     xchg    al,patched    ; clear and test patched
  939.     test    al,al
  940.     jz    patch1        ; z = disabled or done
  941.     xchg    ah,flags.takflg    ; clear take flag -- don't echo patches
  942.     mov    byte ptr temp,ah; but save it
  943.     call    ptchr
  944.     mov    al,byte ptr temp; restore take flag
  945.     mov    flags.takflg,al
  946.     jc    patch2        ; c = NG
  947. patch1:    ret
  948.  
  949. patch2:    mov    dx,offset ermes8; Fatal error
  950.     mov    ah,prstr
  951.     int    dos
  952.     jmp    krmend        ; force exit
  953.  
  954. ptchr:    mov    ax,offset ptchnam ; point to name of patch file
  955.     call    rdini1        ; let rdini try to find it & do take stuff
  956.     jnc    ptch1        ; nc = file mskermit.pch was found
  957.     mov    dx,offset ermes7 ; say file not found
  958.     mov    ah,prstr
  959.     int    dos
  960.     clc
  961.     ret
  962.  
  963. ptch1:    mov    al,taklev    ; remember initial take level
  964.     mov    tmpbuf,al    ; when it changes, it's EOF & we're done
  965.     mov    comand.cmcr,1    ; bare cr's ok, to prevent prserr @EOF
  966.     call    ptchrl        ; read 1st line's 1st 'word'
  967.     jc    ptch2        ; c = trouble
  968.     jz    ptch3        ; z = EOF
  969.     mov    si,offset tmpbuf+1
  970.     call    atoi        ; convert version string to integer
  971.     jc    ptch2        ; c = bad number, or none
  972.     cmp    ax,version    ; does it match this version?
  973.     je    ptch4        ; e = yes
  974. ptch2:    mov    al,tmpbuf    ; if take level has changed,
  975.     xor    al,taklev    ;  we're already out of patch file
  976.     jnz    ptch3        ; nz = change in take level
  977.     call    takclos        ; close patch file
  978. ptch3:    mov    dx,offset ermes6
  979.     mov    ah,prstr    ; issue warning msg
  980.     int    dos
  981.     clc
  982.     ret
  983.  
  984. ptch4:    mov    dx,offset tmpbuf+1
  985.     call    ptchrw        ; read 2nd "word", 1st line
  986.     jc    ptch2        ; c = NG
  987.     mov    si,offset tmpbuf+1
  988.     call    katoi        ; convert 2nd "magic number"
  989.     jc    ptch2        ; c = NG
  990.     cmp    ax,totpar    ; is it the total paragraphs memini computed?
  991.     jne    ptch2        ; ne = no
  992.     mov    bx,offset buff    ; place to stash 1st lines patch/version msg
  993.     xor    dx,dx
  994.     mov    ah,cmline    ; read it
  995.     call    comnd
  996.  
  997. ptch5:    call    ptchrl        ; read CS:xxxx or DS:xxxx
  998.     jc    ptch6
  999.     jz    ptch7        ; z = EOF
  1000.     cmp    ah,7        ; were 7 chars read?
  1001.     jne    ptch6        ; ne = no
  1002.     mov    si,offset tmpbuf+1
  1003.     and    word ptr[si],not 2020h ; convert to upper case
  1004.     cld
  1005.     lodsb            ; get the seg char
  1006.     cmp    word ptr[si],':S' ; S:, actually
  1007.     je    ptch8        ; e = ok
  1008. ptch6:    stc            ; error exit
  1009.     ret
  1010.  
  1011. ptch7:    clc
  1012.     ret
  1013.  
  1014. ptch8:    push    ds
  1015.     pop    es
  1016.     mov    di,offset segstr
  1017.     mov    cx,lsegstr    ; search for seg char in segstr
  1018.     repne    scasb
  1019.     jne    ptch6        ; ne = not found
  1020.     sub    di,offset segstr+1 ; distance spanned
  1021.     shl    di,1        ; make a word index
  1022.     mov    bx,segtab[di]    ; bx = seg-base
  1023.     or    bx,bx        ; seg-base = 0, aren't enabled for patching
  1024.     jz    ptch6        ; z = 0, no patching
  1025.     mov    word ptr[si],'X\' ; put '\X' in front of hex for katoi
  1026.     call    katoi        ; convert location
  1027.     jc    ptch6        ; c= NG
  1028.     push    bx        ; save seg being patched
  1029.     push    ax        ; save location being patched
  1030.     mov    tmpbuf+64,0    ; clear replacement byte count
  1031. ptch9:    mov    dx,offset tmpbuf+4
  1032.     call    ptchrw        ; read replacement byte follwing '\X'
  1033.     jnc    ptch11        ; nc = OK
  1034. ptch10:    pop    ax        ; clean stack & error return
  1035.     pop    bx
  1036.     stc
  1037.     ret
  1038.  
  1039. ptch11:    or    ax,ax        ; EOL?
  1040.     jnz    ptch13        ; nz = no
  1041.     mov    si,offset tmpbuf+64
  1042.     cld
  1043.     lodsb            ; replacement byte count
  1044.     cmp    al,2        ; gotta be at least 2
  1045.     jb    ptch10        ; b = too few
  1046.     mov    cx,ax        ; replacement count
  1047.     pop    di        ; patch location
  1048.     pop    es        ; patch segment
  1049.     lodsb            ; al = comparison byte
  1050.     or    al,al        ; key value to ignore comparison?
  1051.     jz    ptch12        ; z = 0, yes
  1052.     cmp    byte ptr es:[di],al ; do read check on memory image
  1053.     jne    ptch6        ; ne = no match, fail now
  1054. ptch12:    dec    cx        ; adjust for comparison byte
  1055.     rep    movsb        ; make patch
  1056.     jmp    ptch5        ; loop to read next line
  1057.  
  1058. ptch13:    cmp    ah,2        ; 2 chars req'd for replacement byte
  1059.     jne    ptch10        ; ne = bad
  1060.     mov    si,offset tmpbuf+2 ; convert it
  1061.     call    katoi
  1062.     jc    ptch10        ; c = bad number or none
  1063.     mov    si,offset tmpbuf+64    ; --> replacement byte counted string
  1064.     inc    byte ptr[si]    ; bump count
  1065.     mov    bl,[si]
  1066.     xor    bh,bh
  1067.     mov    byte ptr[si+bx],al ; stash replacement byte
  1068.     jmp    short ptch9    ; loop for next byte
  1069.  
  1070. ptchrl:    mov    dx,offset crlf    ; read 1st "word", next line to tmpbuf+1
  1071.     call    prompt
  1072.     mov    dx,offset tmpbuf+1
  1073.     call    ptchrw
  1074.     jc    ptchrb        ; c = NG
  1075.     mov    al,tmpbuf
  1076.     xor    al,taklev
  1077.     jz    ptchra        ; z = not EOF
  1078.     xor    ax,ax        ; set z flag for EOF
  1079.     ret
  1080.  
  1081. ptchra:    or    ah,ah        ; empty or comment line?
  1082.     jz    ptchrl        ; z = empty or comment, ignore
  1083. ptchrb:    ret
  1084.  
  1085. ptchrw:    mov    ah,cmword
  1086.     mov    comand.cmper,1    ; prohibit substitution variable expansion
  1087.     xor    bx,bx        ; 'help' ptr
  1088.     call    comnd
  1089.     xchg    ah,al
  1090.     ret
  1091. PATCH    endp
  1092.  
  1093. ; Get command line into a Take macro buffer. Allow "-f filspec" to override
  1094. ; normal mskermit.ini initialization filespec, allow command "stay" to
  1095. ; suppress automatic exit to DOS at end of command line execution. [jrd]
  1096.  
  1097. gcmdlin    proc    near
  1098.     mov    word ptr decbuf,0    ; storage for new init filename
  1099.     push    es
  1100.     cld
  1101.     mov    es,psp            ; address psp
  1102.     xor    ch,ch
  1103.     mov    cl,es:byte ptr[cline]    ; length of cmd line from DOS
  1104.     jcxz    gcmdl1            ; z = empty line
  1105.     mov    si,cline+1        ; point to actual line
  1106. gcmdl0:    cmp    byte ptr es:[si],' '    ; skip over leading whitespace
  1107.     ja    gcmdl2            ; a = non-whitespace
  1108.     inc    si
  1109.     loop    gcmdl0            ; fall through on all whitespace
  1110. gcmdl1:    jmp    gcmdl14            ; common exit jump point
  1111. gcmdl2:    inc    cx            ; include DOS's c/r
  1112.     call    takopen            ; open take buffer in macro space
  1113.     mov    bx,takadr
  1114.     mov    byte ptr [bx].taktyp,0ffh ; mark as a macro
  1115.     mov    [bx].takcnt,0        ; length of text
  1116.     mov    es,[bx].takbuf        ; segment of buffer, from takopen
  1117.     mov    di,2            ; skip count word
  1118.     push    psp
  1119.     pop    ds            ; DS = PSP
  1120.     xor    dx,dx            ; clear brace count
  1121. gcmdl3:    or    cx,cx            ; anything left?
  1122.     jle    gcmdl10            ; le = no
  1123.     lodsb                ; get a byte from PSP's command line
  1124.     dec    cx            ; one less char in input string
  1125.     cmp    al,','            ; comma?
  1126.     jne    gcmdl4            ; no, keep going
  1127.     or    dx,dx            ; inside braces?
  1128.     jnz    gcmdl9            ; nz = yes, retain embedded commas
  1129.     mov    al,cr            ; convert to cr
  1130.     jmp    short gcmdl9        ; store it
  1131. gcmdl4:    call    bracechk        ; check for curly braces
  1132.     jc    gcmdl9            ; c = found and counted brace
  1133.     or    dx,dx            ; outside braces?
  1134.     jnz    gcmdl9            ; nz = no, ignore flag
  1135.     cmp    al,'-'            ; starting a flag?
  1136.     jne    gcmdl9            ; ne = no
  1137.     mov    ah,[si]            ; get flag letter
  1138.     or    ah,20h            ; convert to lower case
  1139.     cmp    ah,'f'            ; 'f' for init file replacement?
  1140.     jne    gcmdl9            ; ne = no
  1141.     inc    si            ; accept flag letter
  1142.     dec    cx
  1143. gcmdl5:    or    cx,cx            ; anything to read?
  1144.     jle    gcmdl10            ; le = exhausted supply
  1145.     lodsb                ; get filespec char from psp
  1146.     dec    cx            ; one less char in source buffer
  1147.     cmp    al,' '            ; in whitespace?
  1148.     jbe    gcmdl5            ; be = yes, scan it off
  1149.     dec    si            ; backup to real text
  1150.     inc    cx
  1151.                     ; copy filspec to buffer decbuf
  1152.     push    es            ; save current destination pointer
  1153.     push    di            ;  which is in es:di (Take buffer)
  1154.     mov    di,data            ; set es:di to regular decbuf
  1155.     mov    es,di
  1156.     lea    di,decbuf        ; where filespec part goes
  1157.     mov    word ptr es:[di],0    ; plant safety terminator
  1158. gcmdl6:    lodsb                ; get filespec char
  1159.     dec    cx            ; one less available
  1160.     cmp    al,' '            ; in printables?
  1161.     jbe    gcmdl7            ; be = no, all done
  1162.     cmp    al,','            ; comma command separator?
  1163.     je    gcmdl7            ; e = yes, all done
  1164.     stosb                ; store filespec char
  1165.     or    cx,cx            ; any chars left?
  1166.     jg    short gcmdl6        ; g = yes
  1167. gcmdl7:    mov    byte ptr es:[di],0    ; end filespec on a null
  1168.     pop    di            ; recover destination pointer es:di
  1169.     pop    es
  1170. gcmdl8:    or    cx,cx            ; strip trailing whitespace
  1171.     jle    gcmdl10            ; le = nothing left
  1172.     lodsb
  1173.     dec    cx
  1174.     cmp    al,' '            ; white space?
  1175.     jbe    gcmdl8            ; be = yes, strip it
  1176.     cmp    al,','            ; at next command?
  1177.     je    gcmdl10            ; e = yes, skip our own comma
  1178.     dec    si            ; back up to reread the char
  1179.     inc    cx
  1180.     jmp    gcmdl3            ; read more command text
  1181.                     ; end of flag analysis
  1182. gcmdl9:    stosb                ; deposit most recent char
  1183. gcmdl10:or    cx,cx            ; anything left to read?
  1184.     jg    gcmdl3            ; g = yes, loop
  1185.                     ;
  1186.     mov    ax,data            ; restore segment registers
  1187.     mov    ds,ax
  1188.     mov    si,[bx].takbuf        ; get segment of Take buffer
  1189.     mov    es,si
  1190.     mov    si,2            ; skip count word
  1191.     mov    cx,di            ; current end pointer, (save di)
  1192.     sub    cx,si            ; current ptr minus start offset
  1193.     mov    [bx].takcnt,cx        ; chars in buffer so far
  1194.     mov    es:word ptr [0],cx    ; store count word
  1195.     xor    dx,dx            ; brace count
  1196.     or    cx,cx
  1197.     jg    gcmdl11            ; g = material at hand
  1198.     call    takclos            ; empty take file
  1199.     jmp    short gcmdl14        ; finish up
  1200.                     ; scan for command "stay"
  1201. gcmdl11:mov    ax,es:[si]        ; get 2 bytes, cx and si are set above
  1202.     inc    si            ; increment by only one char
  1203.     dec    cx
  1204.     call    bracechk        ; check for braces
  1205.     jc    gcmdl12            ; c = brace found
  1206.     cmp    al,' '            ; separator?
  1207.     jbe    gcmdl12            ; be = yes, keep looking
  1208.     cmp    al,','             ; comma separator?
  1209.     je    gcmdl12            ; e = yes
  1210.     or    dx,dx            ; within braces?
  1211.     jnz    gcmdl12            ; nz = yes, skip STAY search
  1212.     or    ax,2020h        ; convert to lower case
  1213.     cmp    ax,'ts'            ; first two letters of stay
  1214.     jne    gcmdl12            ; ne = no match
  1215.     mov    ax,es:[si+1]        ; next two letters (stay vs status)
  1216.     or    ax,2020h        ; convert to lower case
  1217.     cmp    ax,'ya'            ; same as our pattern?
  1218.     jne    gcmdl12            ; ne = no match
  1219.     add    si,3            ; char after "stay"
  1220.     sub    cx,3
  1221.                     ; check for separator or end of macro
  1222.     cmp    byte ptr es:[si],' '    ; next char is a separator?
  1223.     jbe    gcmdl13            ; be = yes, found correct match
  1224.     cmp    byte ptr es:[si],','    ; or comma separator?
  1225.     je    gcmdl13            ; e = yes
  1226.     or    cx,cx            ; at end of macro?
  1227.     jle    gcmdl13            ; yes, consider current match correct
  1228. gcmdl12:or    cx,cx            ; done yet? ("stay" not found)
  1229.     jg    gcmdl11            ; g = not yet, look some more
  1230.     mov    si,offset eexit        ; append command "exit"
  1231.     mov    cx,leexit        ; length of string "exit"
  1232.     add    [bx].takcnt,cx
  1233.     rep    movsb            ; copy it into the Take buffer
  1234. gcmdl13:mov    [bx].takptr,2        ; init buffer ptr
  1235.     mov    cx,[bx].takcnt        ; count of bytes in buffer
  1236.     mov    es:[0],cx        ; count of bytes in Take buffer
  1237. gcmdl14:pop    es
  1238.     ret
  1239. gcmdlin    endp
  1240.  
  1241. ; Curly brace checker. Examine (and preserve) char in AL. Count up/down
  1242. ; braces in dx because DS is unknown here
  1243. bracechk proc    near
  1244.     cmp    al,braceop        ; opening brace?
  1245.     jne    bracech1        ; ne = no
  1246.     inc    dx            ; count up braces
  1247.     stc                ; say brace seen
  1248.     ret
  1249. bracech1:cmp    al,bracecl        ; closing brace
  1250.     jne    bracech3        ; ne = no
  1251.     sub    dx,1            ; count down with sign
  1252.     jns    bracech2        ; ns = no underflow
  1253.     xor    dx,dx            ; don't go below zero
  1254. bracech2:stc                ; say brace detected
  1255.     ret
  1256. bracech3:clc                ; say brace not found
  1257.     ret
  1258. bracechk endp
  1259.  
  1260. ; Enter with ax pointing to file name.  Searches path for given file,
  1261. ; returns with ax pointing to whole name, or carry set if file can't be found.
  1262. SPATH    proc    near
  1263.     call    isfile            ; does it exist as it is?
  1264.     jc    spath0            ; c = no, prepend path elements
  1265.     test    byte ptr filtst.dta+21,10H ; subdirectory name?
  1266.     jnz    spath0            ; nz = yes, not desired file
  1267.     clc
  1268.     ret
  1269. spath0:    push    es            ; save es around work
  1270.     push    bx
  1271.     push    si
  1272.     push    di
  1273.     mov    bx,ax            ; save filename pointer in bx
  1274.     mov    si,ax
  1275.     xor    dl,dl            ; no '\' seen yet
  1276.     cld
  1277. spath1:    lodsb
  1278.     cmp    al,2fh            ; contains fwd slash path characters?
  1279.     je    spath1a
  1280.     cmp    al,5ch            ; or backslash?
  1281.     jne    spath2            ; no, keep going
  1282. spath1a:mov    dl,1            ; remember we've seen them
  1283. spath2:    or    al,al
  1284.     jnz    spath1            ; copy name in
  1285.     or    dl,dl            ; look at flag
  1286.     jz    spath3            ; no path, keep looking
  1287.     jmp    short spath9        ; embedded path, fail
  1288.  
  1289. spath3:    mov    si,pthadr        ; offset of PATH= string in environment
  1290.     mov    es,psp
  1291.     mov    di,es:word ptr[env]    ; pick up environment segment
  1292.     mov    es,di
  1293. spath4:    cmp    byte ptr es:[si],0    ; end of PATH= string?
  1294.     je    spath9            ; e = yes, exit loop
  1295.     mov    di,offset decbuf+64    ; place to put name
  1296. spath5:    mov    al,byte ptr es:[si]    ; get a byte from environment string
  1297.     inc    si
  1298.     cmp    al,';'            ; end of this part?
  1299.     je    spath7            ; yes, break loop
  1300.     or    al,al            ; maybe end of string?
  1301.     jnz    spath6            ; nz = no, keep going
  1302.     dec    si            ; back up to null for later rereading
  1303.     jmp    short spath7        ; and break loop
  1304. spath6:    mov    byte ptr [di],al    ; else stick in dest string
  1305.     inc    di
  1306.     jmp    short spath5        ; and continue
  1307. spath7:    push    si            ; save this ptr
  1308.     mov    si,bx            ; this is user's file name
  1309.     cmp    byte ptr [di-1],2fh    ; does path end with switch char?
  1310.     je    spath8            ; yes, don't put one in
  1311.     cmp    byte ptr [di-1],5ch    ; how about this one?
  1312.     je    spath8            ; yes, don't put it in
  1313.     mov    byte ptr [di],5ch    ; else add one
  1314.     inc    di
  1315. spath8:    lodsb                ; get filename character
  1316.     mov    byte ptr [di],al    ; copy filename char to output buffer
  1317.     inc    di
  1318.     or    al,al            ; end of string?
  1319.     jnz    spath8            ; nz = no, copy rest of name
  1320.     pop    si            ; restore postion in path string
  1321.     mov    ax,offset decbuf+64
  1322.     call    isfile            ; is it a file?
  1323.     jc    spath4            ; c = no, keep looking
  1324.     test    byte ptr filtst.dta+21,10H ; subdirectory name?
  1325.     jnz    spath4            ; nz = yes
  1326.     pop    di
  1327.     pop    si
  1328.     pop    bx
  1329.     pop    es
  1330.     clc
  1331.     ret                ; return success (carry clear)
  1332. spath9:    mov    ax,bx            ; restore original filename pointer
  1333.     pop    di            ; restore regs
  1334.     pop    si
  1335.     pop    bx
  1336.     pop    es
  1337.     stc                ; no file found
  1338.     ret
  1339. spath    endp
  1340.  
  1341. ; Put offset of PATH= string in pthadr
  1342. getpath    proc    near
  1343.     push    bx
  1344.     push    cx
  1345.     push    dx
  1346.     mov    bx,offset pthnam    ; thing    to find
  1347.     mov    cx,pthlen        ; length of it
  1348.     mov    pthadr,0        ; init offset to zero
  1349.     call    getenv            ; get environment value
  1350.     mov    pthadr,dx
  1351.     pop    dx
  1352.     pop    cx
  1353.     pop    bx
  1354.     ret
  1355. getpath    endp
  1356.  
  1357. ; getcsp: copy COMSPEC= environment string into cmspbuf
  1358. ; getssp: copy SHELL=   environment string into shellbuf
  1359. getcsp    proc    near
  1360.     mov    bx,offset cmspnam    ; find COMSPEC=
  1361.     mov    cx,cmsplen        ; it's length
  1362.     mov    di,offset cmspbuf    ; where to store string
  1363.     jmp    short getccom        ; do common worker
  1364.  
  1365. getssp:    mov    bx,offset shellnam    ; find SHELL=
  1366.     mov    cx,shellen        ; it's length
  1367.     mov    di,offset shellbuf    ; where to store string
  1368.     
  1369. getccom:push    es
  1370.     call    getenv            ; get environment offset into dx
  1371.     mov    si,dx            ; address of COMSPEC= string
  1372.     mov    es,psp
  1373.     mov    bx,es:word ptr[env]    ; pick up environment address
  1374.     mov    es,bx
  1375.     push    ds            ; save ds
  1376.     push    ds            ; make ds point to environment seg
  1377.     push    es            ; make es point to data segment
  1378.     pop    ds
  1379.     pop    es
  1380.     cld
  1381. getcs1:    lodsb                ; get a byte from environment
  1382.     cmp    al,' '            ; space or less?
  1383.     jg    getcs2            ; g = no, keep copying
  1384.     xor    al,al            ; terminate string on spaces etc
  1385. getcs2:    stosb                ; store it in destination
  1386.     or    al,al            ; at end of string yet?
  1387.     jnz    getcs1            ; nz = no, keep copying
  1388.     pop    ds            ; recover ds
  1389.     pop    es
  1390.     ret
  1391. getcsp    endp
  1392.  
  1393. ; Get Kermit parameters from the Environment. Parameters are commands like
  1394. ; regular commands except they do not appear in the SET main table and are
  1395. ; separated from one another by semicolons. They appear after KERMIT=.
  1396. ; Do not allow Take/Macros to be created by any of these commands.
  1397. ; On fatal error exits with carry set and flags.extflg = 1
  1398. getparm    proc    near
  1399.     push    ax
  1400.     push    bx
  1401.     push    cx
  1402.     push    dx
  1403.     push    si
  1404.     push    di
  1405.     push    es
  1406.     mov    es,psp            ; segment of our PSP
  1407.     mov    ax,es:word ptr[env]    ; pick up environment address
  1408.     mov    es,ax
  1409.     mov    bx,offset kerenv    ; Environment word to find, asciiz
  1410.     mov    dx,bx
  1411.     call    strlen            ; length of its string to cx
  1412.     call    getenv            ; return dx = offset in environment
  1413.     jnc    getpar1            ; nc = success
  1414.     jmp    getpar9            ; c = not found
  1415. getpar1:push    ds            ; save regular DS
  1416.     push    dx            ; push Environment offset, then seg
  1417.     push    es
  1418.     call    takopen            ; open Take buffer in macro space
  1419.     jnc    getpar2            ; nc = success
  1420.     mov    flags.extflg,1        ; say exit now
  1421.     pop    es            ; clean stack
  1422.     pop    dx
  1423.     pop    ds
  1424.     jmp    getparx            ; exit with fatal error
  1425.  
  1426. getpar2:mov    bx,takadr        ; bx = Take data structure
  1427.     mov    byte ptr [bx].taktyp,0ffh ; mark as a macro
  1428.     mov    [bx].takcnt,0        ; length of text
  1429.     mov    es,[bx].takbuf        ; ES = segment of buffer, from takopen
  1430.     mov    di,2            ; skip count word field for es:di
  1431.     pop    ds            ; pop Environment segment (was in ES)
  1432.     pop    si            ;  and seg, DS:SI is now Environment
  1433.     xor    cx,cx            ; line length counter
  1434. getpar3:lodsb                ; read an Environment character
  1435.     or    al,al            ; null (EOL)?
  1436.     jz    getpar5            ; z = yes, stop here
  1437.     cmp    al,';'            ; semicolon separator?
  1438.     jne    getpar4            ; ne = no
  1439.     mov    al,CR            ; replace semicolon with carriage ret
  1440. getpar4:stosb                ; store char in Take buffer
  1441.     inc    cx            ; count line length
  1442.     jmp    short getpar3        ; get more text, until a null
  1443.  
  1444. getpar5:mov    al,CR            ; terminate line, regardless
  1445.     stosb
  1446.     inc    cx            ; count terminator
  1447.     pop    ds            ; restore regular DS
  1448.     mov    [bx].takcnt,cx        ; chars in Take/macro buffer
  1449.     mov    es:[0],cx        ; store count byte
  1450.     mov    [bx].takptr,2        ; init buffer read ptr to first char
  1451.     jcxz    getpar8            ; z = nothing left, exit
  1452.                     ; parse each item as a command
  1453. getpar6:mov    comand.cmquiet,1    ; no screen display
  1454.     mov    dx,offset nulprmpt    ; set null prompt
  1455.     call    prompt
  1456.     cmp    flags.extflg,0        ; exit flag set?
  1457.     jne    getpar8            ; ne = yes, exit this routine now
  1458.     mov    dx,offset initab    ; table of initialization routines
  1459.     xor    bx,bx            ; no explict help text
  1460.     mov    comand.cmcr,1        ; allow bare CR's
  1461.     mov    comand.impdo,0        ; do not search Macro table
  1462.         mov    ah,cmkey        ; match a keyword
  1463.     call    comnd
  1464.     jc    getpar7            ; c = failure
  1465.     mov    comand.cmcr,0        ; no more bare CR's
  1466.     call    bx            ; call the routine returned in BX
  1467.                     ; ignore failures (carry bit set)
  1468. getpar7:cmp    taklev,0        ; finished Take file?
  1469.     je    getpar8            ; e = yes
  1470.     cmp    flags.extflg,0        ; exit flag set?
  1471.     je    getpar6            ; e = no, finish all commands
  1472.  
  1473. getpar8:call    takclos            ; close our take file, if open
  1474. getpar9:mov    flags.extflg,0        ; do not leave this flag set
  1475.     clc                ; clear for success
  1476. getparx:mov    comand.cmquiet,0    ; regular screen echoing
  1477.     pop    es
  1478.     pop    di
  1479.     pop    si
  1480.     pop    dx
  1481.     pop    cx
  1482.     pop    bx
  1483.     pop    ax
  1484.     ret
  1485. getparm    endp
  1486.  
  1487. ; Locate string variable in Environment
  1488. ; bx = variable to find (usually including =), cx = length of variable name.
  1489. ; Returns dx = offset within Environment of char following the name and
  1490. ; carry clear, else carry set and dx unchanged.
  1491. getenv    proc    near
  1492.     push    ax
  1493.     push    cx
  1494.     push    si
  1495.     push    di
  1496.     push    es
  1497.     mov    es,psp
  1498.     mov    ax,es:word ptr[env]    ; pick up environment address
  1499.     mov    es,ax
  1500.     xor    di,di            ; start at offset 0 in segment
  1501. geten1:    cmp    es:byte ptr [di],0    ; end of environment?
  1502.     je    geten3            ; yes, forget it
  1503.     push    cx            ; save counter
  1504.     push    di            ; and offset
  1505.     mov    si,bx
  1506.     cld
  1507.     repe    cmpsb            ; search for name
  1508.     pop    di
  1509.     pop    cx            ; restore these
  1510.     je    geten2            ; found it, break loop
  1511. getenv5:push    cx            ; preserve again
  1512.     mov    cx,0ffffh        ; bogus length
  1513.     xor    al,al            ; 0 = marker to look for
  1514.     repne    scasb            ; search for it
  1515.     pop    cx            ; restore length
  1516.     jmp    short geten1        ; loop thru rest of environment
  1517. geten2:    add    di,cx            ; skip to definition
  1518. geten6:    mov    si,bx            ; name
  1519.     add    si,cx            ; length
  1520.     cmp    byte ptr [si-1],'='    ; caller wanted '=' as last char?
  1521.     je    geten7            ; e = yes, and we found it
  1522.     mov    al,es:[di]        ; get next char
  1523.     cmp    al,'='            ; at the equals sign?
  1524.     je    geten7            ; e = yes
  1525.     inc    di            ; point at next char
  1526.     cmp    al,' '            ; white space?
  1527.     jbe    geten6            ; be = yes, skip over this
  1528.     dec    di            ; backup
  1529.     jmp    short getenv5        ; not a match, keep looking
  1530. geten7:    mov    dx,di            ; store offset of string
  1531.     clc                ; carry clear for success
  1532.     jmp    short geten4
  1533. geten3:    stc                ; carry set for failure
  1534. geten4:    pop    es
  1535.     pop    di
  1536.     pop    si
  1537.     pop    cx
  1538.     pop    ax
  1539.     ret
  1540. getenv    endp
  1541.  
  1542. ; Get thousands separator from DOS Country Information
  1543. gettsep    proc    near
  1544.     mov    ah,38h            ; Get Country Information
  1545.     mov    dx,offset tmpbuf    ; temp buffer
  1546.     int    dos
  1547.     mov    bx,7            ; assume DOS 3+ position in buffer
  1548.     cmp    byte ptr dosnum+1,3    ; DOS 3 or above?
  1549.     jae    gettse1            ; ae = yes
  1550.     mov    bx,4            ; for DOS 2.1
  1551.     cmp    dosnum,210h        ; earlier than version 2.1?
  1552.     jae    gettse1            ; ae = no
  1553.     mov    al,','            ; use comma for old DOS's
  1554. gettse1:mov    al,tmpbuf[bx]        ; get thousands separator char
  1555.     mov    thsep,al        ; save it
  1556.     mov    al,tmpbuf        ; get time/date format code
  1557.     mov    tdfmt,al        ; save it
  1558.     ret
  1559. gettsep    endp
  1560.  
  1561. STAY    PROC    NEAR
  1562.     clc
  1563.     ret
  1564. STAY    ENDP
  1565.  
  1566. CLS    proc    near            ; Clear command level screen
  1567.     mov    ah,cmeol        ; get a confirmation
  1568.     call    comnd
  1569.     jc    cls1            ; c = failure
  1570.     call    cmblnk            ; blank the screen
  1571.     call    locate            ; put cursor at home position
  1572. cls1:    ret
  1573. CLS    endp
  1574.  
  1575. COMNT    PROC    NEAR            ; COMMENT command
  1576.     mov    ah,cmline
  1577.     mov    bx,offset tmpbuf
  1578.     xor    dx,dx
  1579.     call    comnd
  1580.     jc    comnt1
  1581.     mov    ah,cmeol
  1582.     call    comnd
  1583. comnt1:    ret
  1584. COMNT    ENDP
  1585.  
  1586. ; change working directory
  1587. cwdir    proc    near
  1588.     mov    kstatus,kssuc        ; global status
  1589.     mov    ah,cmword
  1590.     mov    dx,offset tmpbuf
  1591.     mov    bx,offset pthmsg
  1592.     mov    word ptr tmpbuf,0
  1593.     call    comnd            ; get drive/dir spec, if any
  1594.     mov    ah,cmeol
  1595.     call    comnd
  1596.     jnc    cwd1
  1597.     ret                ; c = failure
  1598. cwd1:    mov    si,offset tmpbuf    ; cdsr wants drive/path ptr in si
  1599.     call    cdsr            ; common CD sub-routine
  1600.     jnc    cwd2            ; nc = success
  1601.     mov    kstatus,ksgen        ; global status for unsuccess
  1602. cwd2:    cmp    taklev,0        ; in a Take file or macro?
  1603.     je    cwd3            ; e = no, do echo
  1604.     cmp    flags.takflg,0        ; ok to echo?
  1605.     je    cwd4            ; e = no
  1606. cwd3:    push    dx
  1607.     mov    dx,offset crlf        ; msgs from cdsr don't include this
  1608.     mov    ah,prstr        ; so let's do it now
  1609.     int    dos
  1610.     pop    dx
  1611.     call    prtasz            ; output current drive/path or err msg
  1612. cwd4:    clc
  1613.     ret
  1614. cwdir    endp
  1615.  
  1616. ; CDSR processes both CD & REM CD.  Entered with si --> drive/path, it returns
  1617. ; dx --> ASCIIZ current drive/path, w/carry clear, if successful, or error msg
  1618. ; w/carry set, if not.
  1619. CDSR    PROC
  1620.     mov    kstatus,kssuc        ; global status
  1621.     xor    cx,cx            ; 0 for default drive, if none
  1622.     cmp    byte ptr[si],ch        ; any drive/path?
  1623.     je    cdsr4            ; e = no, just format current drive/path
  1624.     cmp    byte ptr[si+1],':'    ; is drive specified?
  1625.     jne    cdsr1            ; ne = no
  1626.     mov    cl,[si]            ; drive letter
  1627.     cmp    byte ptr[si+2],ch    ; any path?
  1628.     jne    cdsr1            ; ne = yes
  1629.     mov    word ptr[si+2],'.'    ; append dot+null as path to kludge DOS
  1630. cdsr1:    call    dskspace        ; test for drive, spec'd by cl, ready
  1631.     jnc    cdsr2            ; nc = ready
  1632.     mov    spcmsg3,cl        ; insert drive letter ret'd by dskspace
  1633.     mov    dx,offset spcmsg2+2    ; in err msg.  dx --> msg w/o cr,lf
  1634.     mov    kstatus,ksgen        ; global status
  1635.     ret                ; carry is set
  1636.  
  1637. cdsr2:    mov    dx,si            ; where chdir wants it
  1638.     mov    ah,chdir
  1639.     int    dos
  1640.     jnc    cdsr3            ; nc = success
  1641.     mov    dx,offset ermes4    ; ret carry set, dx --> err msg
  1642.     ret
  1643.  
  1644. cdsr3:    mov    dl,cl            ; uc drive letter ret'd by dskspace
  1645.     sub    dl,'A'            ; A = 0 for seldsk
  1646.     mov    ah,seldsk
  1647.     int    dos
  1648.     inc    dl            ; A = 1 for curdsk
  1649.     mov    curdsk,dl
  1650. cdsr4:    push    si            ; use caller's buffer for cur dr/path
  1651.     mov    ax,':@'            ; al = 'A' - 1, ah = ':'
  1652.     add    al,curdsk        ; al = drive letter
  1653.     mov    [si],ax            ; stash drive:
  1654.     inc    si
  1655.     inc    si
  1656.     mov    byte ptr[si],'\'    ; add \
  1657.     inc    si
  1658.     mov    ah,gcd            ; gcd fills in path as ASCIIZ
  1659.     xor    dl,dl            ; use current drive
  1660.     int    dos
  1661.     pop    dx            ; return caller's buffer pointer in dx
  1662.     clc
  1663.     ret
  1664. CDSR    ENDP
  1665.  
  1666. ; Erase specified file(s). Add protection of ignore hidden, subdir, volume
  1667. ; label and system files. 9 Jan 86 [jrd]
  1668. DELETE    PROC    NEAR            ; includes paths and "?*" wildcards
  1669.     mov    kstatus,kssuc        ; global status
  1670.     mov    si,offset delcmd    ; del command
  1671.     mov    di,offset tmpbuf
  1672.     call    strcpy
  1673.     mov    dx,offset tmpbuf
  1674.     call    strlen            ; get its length
  1675.     add    di,cx            ; point at terminator
  1676.     mov    temp,di            ; remember starting spot
  1677.     mov    ah,cmline        ; get a line
  1678.     mov    bx,di            ; where to place the file spec
  1679.     mov    dx,offset filmsg    ; help message
  1680.     call    comnd
  1681.     jc    delet0            ; c = failure
  1682.     push    ax
  1683.     mov    ah,cmeol
  1684.     call    comnd
  1685.     pop    ax
  1686.     jc    delet0
  1687.     or    ax,ax            ; anything given?
  1688.     jnz    delet1            ; nz = yes
  1689.     mov    ah,prstr
  1690.     mov    dx,offset ermes1    ; say need something
  1691.     int    dos
  1692.     clc                ; say success
  1693. delet0:    mov    kstatus,ksgen        ; global status
  1694.     ret
  1695.  
  1696. delet1:    mov    di,temp            ; start of filespec
  1697.     xor    cl,cl            ; disk drive letter
  1698.     cmp    byte ptr [di+1],':'    ; drive specified?
  1699.     jne    delet2            ; ne = no
  1700.     mov    cl,[di]            ; get drive letter
  1701. delet2:    call    dskspace        ; compute space, get letter into CL
  1702.     jnc    delet3            ; nc = success
  1703.     mov    spcmsg3,cl        ; put drive letter in msg
  1704.     mov    dx,offset spcmsg2    ; error message
  1705.     call    prtasz
  1706.     mov    kstatus,ksgen        ; global status
  1707.     clc
  1708.     ret                ; and ignore this command
  1709. delet3:    mov    si,offset tmpbuf    ; del cmd
  1710.     jmp    crun            ; join run cmd from there
  1711. DELETE    ENDP
  1712.  
  1713. ; Space <optional drive letter>
  1714.  
  1715. CHKDSK    PROC    NEAR            ; Space command
  1716.     mov    kstatus,kssuc        ; global status
  1717.     mov    dx,offset tmpbuf    ; buffer
  1718.     mov    tmpbuf,0        ; init to null
  1719.     mov    bx,offset dskmsg    ; help message
  1720.     mov    ah,cmword        ; get optional drive letter
  1721.     call    comnd            ; ignore errors
  1722.     mov    ah,cmeol
  1723.     call    comnd
  1724.     jnc    chkdsk1            ; nc = success
  1725.     ret                ; failure
  1726. chkdsk1:mov    cl,tmpbuf        ; set drive letter
  1727.     call    dskspace        ; compute space, get letter into CL
  1728.     jnc    chkdsk2            ; nc = success
  1729.     and    cl,5fh            ; to upper case
  1730.     mov    spcmsg3,cl        ; insert drive letter
  1731.     mov    dx,offset spcmsg2    ; say drive not ready
  1732.     call    prtasz
  1733.     mov    kstatus,ksgen        ; global status
  1734.     clc
  1735.     ret
  1736.     
  1737. chkdsk2:mov    spcmsg1,cl        ; insert drive letter
  1738.     mov    di,offset tmpbuf    ; work space for lnout
  1739.     mov    word ptr[di],0a0dh    ; cr/lf
  1740.     mov    word ptr[di+2],'  '    ; add two spaces
  1741.     add    di,4
  1742.     call    lnouts            ; use thousands separator
  1743.     mov    si,offset spcmsg
  1744.     call    strcat            ; add text to end of message
  1745.     mov    dx,offset tmpbuf
  1746.     call    prtasz            ; print asciiz string
  1747.     clc
  1748.     ret
  1749. CHKDSK    ENDP
  1750.  
  1751. ; Compute disk free space (bytes) into long word dx:ax.
  1752. ; Enter with disk LETTER in CL (use null if current disk).
  1753. ; Returns uppercase drive letter in CL.
  1754. ; Returns carry set if drive access error. Changes AX, DX.
  1755.  
  1756. DSKSPACE PROC    NEAR
  1757.     mov    dl,cl            ; desired disk letter, or null
  1758.     or    dl,dl            ; use current disk?
  1759.     jnz    dskspa1            ; nz = no
  1760.     mov    ah,gcurdsk        ; get current disk
  1761.     int    dos
  1762.     add    al,'A'            ; make 0 ==> A
  1763.     mov    dl,al
  1764. dskspa1:and    dl,5fh            ; convert to upper case
  1765.     mov    cl,dl            ; return upper case drive letter in CL
  1766.     sub    dl,'A'-1        ; 'A' is 1, etc
  1767.     push    bx
  1768.     push    cx
  1769.     mov    ah,36h            ; get disk free space, bx=sect/cluster
  1770.     int    dos            ; dx:ax=sectors, cx=bytes/sector
  1771.     cmp    ax,0ffffh        ; error response?
  1772.     jne    dskspa2            ; ne = no
  1773.     pop    cx
  1774.     pop    bx
  1775.     stc                ; return error
  1776.     ret
  1777. dskspa2:mul    bx            ; sectors/cluster * clusters = sectors
  1778.     mov    bx,dx            ; save high word of sectors (> 64K)
  1779.     mul    cx            ; bytes = sectors * bytes/sector
  1780.     push    ax            ; save low word of bytes
  1781.     mov    ax,bx            ; recall sectors high word
  1782.     mov    bx,dx            ; save current bytes high word
  1783.     mul    cx            ; high word sectors * bytes/sector
  1784.     add    ax,bx            ; new high bytes + old high bytes
  1785.     mov    dx,ax            ; store high word in dx
  1786.     pop    ax            ; space is in dx:ax as a long word
  1787.     pop    cx
  1788.     pop    bx
  1789.     clc
  1790.     ret
  1791. DSKSPACE ENDP
  1792.  
  1793. ; Get directory    listing
  1794. DIRECT    PROC    NEAR
  1795.     mov    kstatus,kssuc        ; global status
  1796.     mov    si,offset dircmd    ; dir command
  1797.     mov    di,offset tmpbuf
  1798.     call    strcpy
  1799.     mov    dx,offset tmpbuf
  1800.     call    strlen            ; get its length
  1801.     add    di,cx            ; point at terminator
  1802.     mov    temp,cx            ; remember length
  1803.     mov    ah,cmline        ; parse with cmline to allow switches
  1804.     mov    bx,di            ; next available byte
  1805.     mov    dx,offset filmsg    ; help message 
  1806.     call    comnd
  1807.     jnc    direct1            ; nc = success
  1808. direct0:mov    kstatus,ksgen        ; global status
  1809.     ret                ; failure
  1810. direct1:mov    ah,cmeol
  1811.     call    comnd
  1812.     jc    direct0
  1813.     mov    word ptr [bx],0        ; plant terminator
  1814.     mov    cl,curdsk        ; current drive number ('A'=1)
  1815.     add    cl,'A'-1        ; make a letter
  1816.     mov    si,offset tmpbuf
  1817.     push    si
  1818.     add    si,temp            ; user's text after ' dir '
  1819.     cmp    byte ptr [si+1],':'    ; drive specified?
  1820.     jne    direct2            ; ne = no, use current drive
  1821.     mov    cl,[si]            ; get drive letter from buffer
  1822. direct2:call    dskspace        ; check for drive ready
  1823.     pop    si
  1824.     jnc    direct3            ; nc = drive ready
  1825.     mov    spcmsg3,cl        ; insert letter
  1826.     mov    dx,offset spcmsg2    ; say drive is not ready
  1827.     call    prtasz
  1828.     mov    kstatus,ksgen        ; global status
  1829.     stc
  1830.     ret
  1831. direct3:jmp    crun            ; join run cmd from there
  1832. DIRECT    ENDP
  1833.  
  1834. ; This is the 'HELP' command.  It gives a list of the commands
  1835.  
  1836. HELP    PROC    NEAR
  1837.     mov    kstatus,kssuc        ; global status
  1838.     mov    ah,cmeol
  1839.     call    comnd            ; get a confirm
  1840.     jnc    help1            ; nc = success
  1841.     ret                ; failure
  1842.  
  1843. help1:    push    ds            ; changing data segments!
  1844.     push    es
  1845.     mov    ax,ds
  1846.     mov    es,ax            ; for escchr
  1847.     mov    ax,data1        ; new data segment
  1848.     mov    ds,ax
  1849.     ; warning
  1850.     assume    ds:data1
  1851.     mov    ah,prstr        ; show Quick help summary screen
  1852.     mov    dx,offset qckhlp
  1853.     int    dos
  1854.     mov    ah,conout
  1855.     mov    dl,es:trans.escchr    ; get Kermit escape character
  1856.     add    dl,40h            ; convert to printable
  1857.     push    dx            ; save it for repeats below
  1858.     int    dos
  1859.     mov    ah,prstr
  1860.     mov    dx,offset qckhlp1    ; more help text
  1861.     int    dos
  1862.     mov    ah,conout
  1863.     pop    dx
  1864.     push    dx
  1865.     int    dos
  1866.     mov    ah,prstr
  1867.     mov    dx,offset qckhlp2    ; more help text
  1868.     int    dos
  1869.     pop    dx            ; recover current escape char
  1870.     mov    ah,conout
  1871.     int    dos
  1872.     mov    ah,prstr
  1873.     mov    dx,offset qckhlp3    ; end of help message
  1874.     int    dos
  1875.     mov    ah,coninq        ; get a keystroke, quietly
  1876.     int    dos
  1877.     cmp    es:flags.cxzflg,'C'    ; Control-C?
  1878.     je    helpend            ; e = yes, quit now
  1879.     cmp    al,3
  1880.     je    helpend
  1881.     cmp    al,' '            ; space bar?
  1882.     je    help2            ; ne = no, skip second screen
  1883.     jmp    short helpend        ; switch data segments
  1884.  
  1885. help2:    mov    ah,prstr        ; show second Quick help summary
  1886.     mov    dx,offset qckhlp5
  1887.     int    dos
  1888.     mov    ah,coninq
  1889.     int    dos
  1890.     cmp    es:flags.cxzflg,'C'    ; Control-C?
  1891.     je    helpend            ; e = yes, quit now
  1892.     cmp    al,3
  1893.     je    helpend
  1894.     cmp    al,'?'            ; query mark?
  1895.     je    helpquery        ; e = yes do main query help
  1896.     mov    ah,prstr
  1897.     mov    dx,offset qckhlp6
  1898.     int    dos
  1899.     mov    ah,coninq
  1900.     int    dos
  1901.     cmp    es:flags.cxzflg,'C'    ; Control-C?
  1902.     je    helpend            ; e = yes, quit now
  1903.     cmp    al,3
  1904.     je    helpend
  1905.     cmp    al,'?'            ; query mark?
  1906.     je    helpquery        ; e = yes do main query help
  1907.     mov    ah,prstr
  1908.     mov    dx,offset qckhlp7
  1909.     int    dos
  1910. helpend:pop    es
  1911.     pop    ds            ; restore regular data seg data
  1912.     ; warning
  1913.     assume    ds:data
  1914.     clc
  1915.     ret
  1916. helpquery:
  1917.     pop    es
  1918.     pop    ds            ; restore regular data seg data
  1919.     ; warning
  1920.     assume    ds:data
  1921.     mov    ah,prstr        ; show help summary screen
  1922.     mov    dx,offset crlf        ; a few blank lines
  1923.     int    dos
  1924.     int    dos
  1925.     int    dos
  1926.     mov    dx,offset tophlp    ; show usual cryptic help
  1927.     int    dos
  1928. helpx:    clc
  1929.     ret
  1930. HELP    ENDP
  1931.  
  1932. ; the version command - print our version number
  1933. prvers    proc    near
  1934.     mov    kstatus,kssuc        ; global status
  1935.     mov    ah,cmeol
  1936.     call    comnd
  1937.     jc    prvers1            ; c = failure
  1938.     mov    ah,prstr
  1939.     mov    dx,offset crlf
  1940.     int    dos
  1941.     mov    ah,prstr
  1942.     mov    dx,offset machnam    ; display machine name
  1943.     int    dos
  1944.     mov    ah,prstr        ; display the version header
  1945.     mov    dx,offset verident
  1946.     int    dos
  1947.     clc
  1948. prvers1:ret
  1949. prvers    endp
  1950.  
  1951. ; SHOW command dispatcher
  1952. showcmd    proc    near
  1953.     mov    ah,cmkey
  1954.     mov    dx,offset shotab
  1955.     xor    bx,bx            ; no canned help
  1956.     call    comnd
  1957.     jc    showc1            ; c = failure
  1958.     jmp    bx            ; execute the handler
  1959. showc1:    ret                ; failure
  1960. showcmd    endp
  1961.  
  1962. ; the type command - type out a file
  1963. typec    proc    near
  1964.     mov    kstatus,kssuc        ; global status
  1965.     mov    si,offset typcmd    ; type command
  1966.     mov    di,offset tmpbuf
  1967.     call    strcpy
  1968.     mov    dx,offset tmpbuf
  1969.     call    strlen            ; get its length
  1970.     add    di,cx            ; point at terminator
  1971.     mov    temp,di            ; save place for later
  1972.     mov    ah,cmline        ; parse with cmline, allows | more
  1973.     mov    bx,di            ; next available byte
  1974.     mov    dx,offset filmsg    ; In case user wants help
  1975.     call    comnd
  1976.     jc    typec1            ; c = failure
  1977.     push    ax
  1978.     mov    ah,cmeol
  1979.     call    comnd
  1980.     pop    ax
  1981.     jc    typec1
  1982.     or    ax,ax            ; any text given?
  1983.     jnz    typec2            ; nz = yes
  1984.     mov    ah,prstr
  1985.     mov    dx,offset ermes1    ; say need more info
  1986.     int    dos
  1987.     mov    kstatus,ksgen        ; global status
  1988.     clc
  1989. typec1:    ret
  1990. typec2:    mov    byte ptr [bx],0        ; plant terminator
  1991.     mov    si,temp            ; start of filespec
  1992.     xor    cl,cl            ; say local drive
  1993.     cmp    byte ptr [si+1],':'    ; drive given?
  1994.     jne    typec3            ; ne = no
  1995.     mov    cl,[si]            ; get drive letter
  1996. typec3:    call    dskspace        ; check for drive ready
  1997.     jnc    typec4
  1998.     mov    spcmsg3,cl        ; put drive letter in msg
  1999.     mov    dx,offset spcmsg2    ; error message
  2000.     call    prtasz
  2001.     mov    kstatus,ksgen        ; global status
  2002.     clc
  2003.     ret                ; and ignore this command
  2004. typec4:    mov    si,offset tmpbuf
  2005.     jmp    short crun        ; join run cmd from there
  2006. typec    endp
  2007.  
  2008. ; PUSH to DOS (run another copy of Command.com or equiv)
  2009. ; entry fpush (fast push...) pushes without waiting for a confirm
  2010. dopush    proc    near
  2011.     mov    ah,cmeol
  2012.     call    comnd
  2013.     jnc    fpush            ; nc = success
  2014.     ret                ; failure
  2015. fpush:    mov    si,offset tmpbuf    ; a dummy buffer
  2016.     mov    byte ptr [si],0        ; plant terminator
  2017.     mov    dx,offset cmspbuf    ; always use command.com
  2018.     cmp    shellbuf,0        ; SHELL= present?
  2019.     je    crun4            ; e = no, use COMSPEC= name
  2020.     mov    dx,offset shellbuf    ; use SHELL= name
  2021.     jmp    short crun4        ; go run it
  2022. dopush    endp
  2023.  
  2024. ; Run a program from within Kermit
  2025. RUN    PROC    NEAR
  2026.     mov    ah,cmline        ; get program name and any arguments
  2027.     mov    bx,offset tmpbuf    ; place for user's text
  2028.     mov    dx,offset runmsg    ; In case user wants help
  2029.     call    comnd
  2030.     jnc    run1            ; nc = success
  2031.     ret                ; failure
  2032. run1:    or    ax,ax            ; byte count
  2033.     jnz    run2            ; nz = have program name
  2034.     mov    ah,prstr        ; else complain
  2035.     mov    dx,offset ermes1    ; need more info
  2036.     int    dos
  2037.     clc
  2038.     ret
  2039. run2:    mov    si,offset tmpbuf    ; source of text
  2040.     jmp    short crun
  2041. RUN    ENDP
  2042.  
  2043. ; crun - run an arbitrary program.    Rewritten by [jrd]
  2044. ; Enter with ordinary asciiz command in si (such as Dir *.asm)
  2045. ; Append a c/r and a null terminator and then ask command.com to do it
  2046. ; Set errlev with DOS errorlevel from subprocess.
  2047. CRUN    proc    near
  2048.     mov    ah,prstr        ; output crlf before executing comnd
  2049.     mov    dx,offset crlf        ; [lba]
  2050.     int    dos
  2051.     mov    di,offset tmpbuf    ; where to put full command line text
  2052.     cmp    si,di            ; same place?
  2053.     je    crun1            ; e = yes, don't copy ourself
  2054.     call    strcpy            ; si holds source text
  2055. crun1:    mov    si,offset slashc    ; DOS command begins with slashc area
  2056.     mov    dx,offset slashc+1    ; si points to /c part of command line
  2057.     call    strlen            ; get its length into cx
  2058.     push    bx
  2059.     mov    bx,dx
  2060.     add    bx,cx
  2061.     mov    byte ptr [bx],cr    ; end string with a c/r for dos
  2062.     inc    cx            ; count the c/r
  2063.     mov    byte ptr [bx+1],0    ; and terminate
  2064.     pop    bx
  2065.     mov    [si],cl            ; put length of argument here
  2066.     mov    dx,offset cmspbuf    ; always use command.com
  2067. crun4:    mov    exearg+2,si        ; pointer to argument string
  2068.     mov    exearg+4,ds        ; segment of same
  2069.     cmp    lclsusp,0        ; sys dependent routine to call
  2070.     je    crun5            ; e = none
  2071.     mov    bx,lclsusp        ; address to call
  2072.     push    dx            ; preserve name in dx
  2073.     call    bx            ; call sys dependent suspend routine
  2074.     pop    dx
  2075. crun5:    push    dx            ; preserve name in dx
  2076.     call    serrst            ; reset serial port (if active)
  2077.     call    cbrestore        ; restore state of Control-Break Chk
  2078.     pop    dx
  2079.     mov    es,psp            ; point to psp again
  2080.     mov    exearg+8,es        ; segment of psp, use our def fcb's
  2081.     mov    exearg+12,es        ; segment of psp, ditto, for fcb 2
  2082.     mov    ax,es:word ptr [env]    ; get environment ptr
  2083.     mov    exearg,ax        ; put into argument block
  2084.     mov    ax,ds
  2085.     mov    es,ax            ; put es segment back
  2086.     mov    bx,offset exearg    ; es:bx points to exec parameter block
  2087.     mov    ax,ss            ; save ss:sp
  2088.     mov    word ptr ssave+2,ax
  2089.     mov    word ptr ssave,sp
  2090.     xor    al,al            ; 0 = load and execute (DX has name)
  2091.     mov    ah,exec
  2092.     int    dos            ; go run the program
  2093.     mov    ax,data            ; restore segment registers
  2094.     mov    ds,ax            ; reset data segment
  2095.     mov    es,ax            ; and extra segment
  2096.     cli
  2097.     mov    ax,word ptr ssave+2
  2098.     mov    ss,ax            ; and stack segment
  2099.     mov    sp,word ptr ssave    ; restore stack ptr
  2100.     sti
  2101.     jc    crun8            ; c = error, handle
  2102.     mov    ah,4dh            ; get subprocess return status
  2103.     int    dos
  2104.     mov    errlev,al        ; DOS errorlevel
  2105.     jmp    short crun9
  2106. crun8:    mov    ah,prstr        ; failure, complain
  2107.     mov    dx,offset erms37
  2108.     int    dos
  2109.     mov    kstatus,ksgen        ; global status
  2110. crun9:    mov    ah,setdma        ; restore dma buffer pointer
  2111.     mov    dx,offset buff
  2112.     int    dos            ; restore dma address!!
  2113.     call    cboff            ; turn off DOS BREAK check
  2114.     cmp    lclrest,0        ; sys dependent routine to call?
  2115.     je    crun10            ; e = none
  2116.     mov    bx,lclrest        ; get routine's address
  2117.     call    bx            ; call sys dependent restore routine
  2118. crun10:    clc
  2119.     ret
  2120. CRUN    ENDP
  2121. code    ends
  2122.  
  2123. code1    segment
  2124.     assume    cs:code1 
  2125. ; Replace Int 23h and Int 24h with our own handlers
  2126. ; Revised to ask DOS for original interrupt vector contents, as suggested by
  2127. ; Jack Bryans. 9 Jan 1986 jrd
  2128. ; Modified again 30 August 1986 [jrd]
  2129. SETINT    PROC    FAR
  2130.     push    es            ; save registers
  2131.     mov    al,23H            ; desired interrupt vector (^C)
  2132.     mov    ah,35H            ; Int 21H, function 35H = Get Vector
  2133.     int    dos            ; get vector in es:bx
  2134.     mov    in3ad,bx        ; save offset of original vector
  2135.     mov    in3ad+2,es        ;   and its segment
  2136.     mov    al,24h            ; DOS critical error, Int 24h
  2137.     mov    ah,35h
  2138.     int    dos
  2139.     mov    word ptr ceadr,bx    ; DOS's Critical Error handler, offset
  2140.     mov    word ptr ceadr+2,es    ;  and segment address
  2141.     push    ds            ; save ds around next DOS calls
  2142.     mov    ax,seg intbrk        ; compose full address of ^C routine
  2143.     mov    ds,ax            ; segment is the code segment
  2144.     mov    dx,offset intbrk    ;   and offset is intbrk
  2145.     mov    al,23H            ; on ^C, goto intbrk
  2146.     mov    ah,25H            ; set interrupt address from ds:dx
  2147.     int    dos
  2148.     mov    dx,offset dosce        ; replacement Critical Error handler
  2149.     mov    al,24h            ; interrupt 24h
  2150.     mov    ah,25h            ; replace it
  2151.     int    dos
  2152.     pop    ds
  2153.     mov    ax,3300h        ; get state of Control-Break Check
  2154.     int    dos
  2155.     mov    orgcbrk,dl        ; save state here
  2156.     pop    es
  2157.     ret
  2158. SETINT    ENDP
  2159.  
  2160. ; Control Break, Interrupt 23h replacement
  2161. ; Always return with a Continue (vs Abort) condition since Kermit will cope
  2162. ; with failures. [jrd]
  2163. intbrk:    push ax
  2164.     push    ds    
  2165.     mov    ax,data            ; get Kermit's data segment
  2166.     mov    ds,ax
  2167.     mov    flags.cxzflg,'C'    ; say we saw a ^C
  2168.     mov    rstate,'E'
  2169.     mov    sstate,'E'
  2170.     pop    ds
  2171.     pop    ax
  2172.     iret               ; return to caller in a Continue condition
  2173.  
  2174. ; Kermit's DOS Critical Error Handler, Int 24h. [jrd]
  2175. ; Needed to avoid aborting Kermit with the serial port interrupt active and
  2176. ; the Control Break interrupt redirected. See the DOS Tech Ref Manual for
  2177. ; a start on this material; it is neither complete nor entirely accurate
  2178. ; The stack is the Kermit's stack, the data segment is unknown, interrupts
  2179. ; are off, and the code segment is Kermit's. Note: some implementations of
  2180. ; MS DOS may leave us in DOS's stack. Called by a DOS Int 21h function
  2181. dosce:    test    ah,80h        ; block device (disk drive)?
  2182.     jnz    dosce1        ; nz = no; serial device, memory, etc
  2183.     mov    al,3        ; tell DOS to Fail the Int 21h call
  2184.     iret            ; return to DOS
  2185. dosce1:    add    sp,6        ; pop IP, CS, Flags regs, from DOS's Int 24h
  2186.     pop    ax        ; restore original callers regs existing
  2187.     pop    bx        ;  just before doing Int 21h call
  2188.     pop    cx
  2189.     pop    dx
  2190.     pop    si
  2191.     pop    di
  2192.     pop    bp
  2193.     pop    ds
  2194.     pop    es        
  2195.     mov    al,0ffh        ; signal failure (usually) the DOS 1.x way
  2196.     push    bp        ; Kermit's IP, CS, and Flags are on the stack
  2197.     mov    bp,sp        ;  all ready for an iret, but first a word ..
  2198.     or    word ptr[bp+8],1 ; set carry bit, signals failure DOS 2+ way
  2199.     pop    bp        ; this avoids seeing the Interrupt flag bit
  2200.     iret            ; return to user, simulate return from Int 21h
  2201. code1    ends
  2202.  
  2203. code    segment
  2204.     assume    cs:code
  2205.  
  2206. ; Set DOS' Control-Break Check to off
  2207. cboff    proc    near
  2208.     mov    ax,3301h        ; set Control-Break Chk state
  2209.     xor    dl,dl            ; set state to off
  2210.     int    dos
  2211.     ret
  2212. cboff    endp
  2213.  
  2214. ; Restore DOS's Control-Break Check to startup value
  2215. cbrestore proc    near
  2216.     push    dx
  2217.     mov    ax,3301h        ; set Control-Break Chk state
  2218.     mov    dl,orgcbrk        ; restore state to startup value
  2219.     int    dos
  2220.     pop    dx
  2221.     ret
  2222. cbrestore endp
  2223.  
  2224. ISFILE    PROC    NEAR
  2225. ; Enter with ds:ax pointing at asciiz filename string
  2226. ; Returns carry set if the file pointed to by ax does not exist, else reset
  2227. ; Returns status byte, fstat, with DOS status and high bit set if major error
  2228. ; Does a search-for-first to permit paths and wild cards
  2229. ; Examines All kinds of files (ordinary, subdirs, vol labels, system,
  2230. ;  and hidden). Upgraded to All kinds on 27 Dec 1985. Revised 30 Aug 86 [jrd]
  2231. ; All registers are preserved
  2232.     push    bx
  2233.     push    ax
  2234.     mov    bx,ax
  2235.     mov    ax,[bx]
  2236.     and    ax,not 2020h        ; to upper
  2237.     cmp    ax,'UN'            ; look for DOS 5 NUL
  2238.     jne    isfil4            ; ne = mismatch
  2239.     mov    ax,[bx+2]
  2240.     and    al,not 20h
  2241.     cmp    ax,'L'+0
  2242.     jne    isfil4            ; ne = mismatch
  2243.     pop    ax
  2244.     pop    bx
  2245.     clc                ; say success
  2246.     ret
  2247. isfil4:    pop    ax
  2248.     pop    bx
  2249.     push    dx            ; save regs
  2250.     push    cx
  2251.     push    ax
  2252.     mov    byte ptr filtst.dta+21,0 ; clear old attribute bits
  2253.     mov    byte ptr filtst.fname,0    ; clear any old filenames
  2254.     mov    filtst.fstat,0        ; clear status byte
  2255.     mov     cx,3fH            ; look at all kinds of files
  2256.     mov    dx,offset filtst.dta    ; own own temporary dta
  2257.     mov    ah,setdma        ; set to new dta
  2258.     int    dos
  2259.     pop    dx            ; get ax (filename string ptr)
  2260.     push    dx            ; save it again
  2261.     mov    ah,first2        ; search for first
  2262.     int    dos
  2263.     pushf                ; save flags
  2264.     mov    dx,offset buff        ; reset dma
  2265.     mov    ah,setdma
  2266.     int    dos
  2267.     popf                ; recover flags
  2268.     jnc    isfil1            ; nc = file found
  2269.     mov    filtst.fstat,al        ; record DOS status
  2270.     cmp    al,2            ; just "File Not Found"?
  2271.     je    isfil2            ; e = yes
  2272.     cmp    al,3            ; "Path not found"?
  2273.     je    isfil2            ; e = yes
  2274.     cmp    al,18            ; "No more files"?
  2275.     je    isfil2            ; e = yes
  2276.     or    filtst.fstat,80h    ; set high bit for more serious error
  2277.     jmp    short isfil2    
  2278. isfil1:    cmp    byte ptr filtst.fname,0    ; did DOS fill in a name?
  2279.     je    isfil2            ; z = no
  2280.     clc
  2281.     jmp    short isfil3
  2282. isfil2:    stc                ; else set carry flag bit
  2283. isfil3:    pop    ax
  2284.     pop    cx
  2285.     pop    dx
  2286.     ret                ; DOS sets carry if file not found
  2287. ISFILE    ENDP
  2288.  
  2289. ; initialize memory usage by returning to DOS anything past the end of kermit
  2290. memini    proc    near
  2291.     push    es
  2292.     mov    bx,_TEXT
  2293.     sub    bx,psp
  2294.     mov    totpar,bx        ; save for patcher's magic number
  2295.     mov    es,psp            ; address psp segment again
  2296.     mov    bx,offset msfinal + 15    ; end of pgm + roundup
  2297.     mov    cl,4
  2298.     shr    bx,cl            ; compute # of paragraphs in last seg
  2299.     mov    ax,_STACK        ; last segment
  2300.     sub    ax,psp            ; minus beginning
  2301.     add    bx,ax            ; # of paragraphs occupied
  2302.     mov    ah,setblk
  2303.     int    dos
  2304.     pop    es
  2305.     jnc    memin1
  2306.     mov    dx,offset ermes2
  2307.     mov    ah,prstr
  2308.     int    dos            ; complain
  2309.     jmp    krmend            ; exit Kermit now
  2310. memin1:    pop    dx            ; save return address here
  2311.     mov    ax,_STACK        ; move SS down to DGROUP, adj SP
  2312.     sub    ax,DGROUP        ; paragraphs to move
  2313.     mov    cl,4            ; convert to bytes
  2314.     shl    ax,cl
  2315.     mov    bx,SP            ; current SP offset
  2316.     add    bx,ax            ; new SP, same memory cell
  2317.     mov    ax,bx
  2318.     sub    ax,400            ; top 400 bytes = Kermit
  2319.     mov    tcptos,ax        ; report this as TCP's top of stack
  2320.     mov    ax,DGROUP        ; new SS
  2321.     cli
  2322.     mov    SS,ax
  2323.     mov    SP,bx            ; whew!
  2324.     sti
  2325.     push    dx            ; push return address
  2326.     clc
  2327.     ret
  2328. memini    endp
  2329.  
  2330. ; Allocate memory.  Passed a memory size in ax, allocates that many
  2331. ; bytes (actually rounds up to a paragraph) and returns its SEGMENT in ax
  2332. ; The memory is NOT initialized.  Written by [jrd] to allow memory to
  2333. ; be allocated anywhere in the 1MB address space
  2334. sbrk    proc    near            ; K & R, please forgive us
  2335.     mov    bx,ax            ; bytes wanted
  2336.     add    bx,15            ; round up
  2337.     mov    cl,4
  2338.     shr    bx,cl            ; convert to # of paragraphs
  2339.     mov    cx,bx            ; remember quantity wanted
  2340.     mov    ah,alloc        ; DOS memory allocator
  2341.     int    dos
  2342.     jc    sbrkx            ; c = fatal
  2343.     cmp    cx,bx            ; paragraphs wanted vs delivered
  2344.     jb    sbrkx            ; b = not enough, fatal error
  2345.     ret                ; and return segment in ax
  2346. sbrkx:    mov    dx,offset mfmsg        ; assume not enough memory (ax = 8)
  2347.     cmp    ax,7            ; corrupted memory (ax = 7)?
  2348.     jne    sbrkx1            ; ne = no
  2349.     mov    dx,offset mf7msg    ; corrupted memory found
  2350. sbrkx1:    mov    ah,prstr
  2351.     int    dos
  2352.     jmp    krmend            ; exit Kermit now
  2353. sbrk    endp
  2354. code     ends
  2355.     end    start
  2356.